summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2019-03-15 13:22:00 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2019-03-15 13:22:00 +0000
commita062971fb96ae7154d88ab408f899f56aaf6df6b (patch)
tree9907dea0824c38373ef2913fd84385ed07a56c3a /usr/src
parent0b570b3cb1c0bf505f1b1bd352664d638b8cc359 (diff)
parentb4a8b33babbf9a7a5de61ea06d09e1eb537f1f6e (diff)
downloadillumos-joyent-a062971fb96ae7154d88ab408f899f56aaf6df6b.tar.gz
[illumos-gate merge]
commit b4a8b33babbf9a7a5de61ea06d09e1eb537f1f6e 10483 aac: cast between incompatible function types commit a00b240dc61ea7ab64e3881b755fca973a531e89 10146 core_pcbe_event_coverage() is missing an else commit 542a7b7f5ccc44e3c95d6dce4ec0566f60bd9ff4 7780 mdb could extract NT_PRPSINFO information from core files commit 2f7dba3e6747cbaaf1deb86e6ca1e2a5c96332ac 10524 wsdiff much slower after move from deprecated commands module 10448 wsdiff explodes on encoding error 10525 wsdiff output is not correct for a binary file 10526 wsdiff tries to spawn 4.8 threads commit adee678425979226b2b55d1a0b39ce4c989382e9 9735 Need to provide SMB 2.1 Client commit 40c0e2317898b8c774791bdc2b30bd50111ab1fa 9875 SMB client connection setup rework commit 8329232e00f1048795bae53acb230316243aadb5 9874 Add fksmbcl development tool Conflicts: usr/src/cmd/mdb/common/modules/libc/libc.c
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/smbclnt/Makefile4
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc24
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile104
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/README99
-rwxr-xr-xusr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh32
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d68
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c98
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c150
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c143
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c938
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/shares.c (renamed from usr/src/cmd/fs.d/smbclnt/test/srvenum.c)236
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/Makefile4
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c143
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/view.c19
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/Makefile85
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/srvinfo.c415
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/tconn.c171
-rw-r--r--usr/src/cmd/mdb/Makefile.common4
-rw-r--r--usr/src/cmd/mdb/Makefile.module4
-rw-r--r--usr/src/cmd/mdb/common/modules/libc/libc.c222
-rw-r--r--usr/src/cmd/mdb/common/modules/nsmb/nsmb.c98
-rw-r--r--usr/src/cmd/mdb/common/modules/smbfs/smbfs.c63
-rw-r--r--usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile49
-rw-r--r--usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile56
-rw-r--r--usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile48
-rw-r--r--usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile55
-rw-r--r--usr/src/common/smbclnt/smbfs_ntacl.c29
-rw-r--r--usr/src/common/smbclnt/smbfs_ntacl.h6
-rw-r--r--usr/src/head/signal.h2
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/libfakekernel/Makefile.com7
-rw-r--r--usr/src/lib/libfakekernel/common/copy.c30
-rw-r--r--usr/src/lib/libfakekernel/common/cred.c60
-rw-r--r--usr/src/lib/libfakekernel/common/kmisc.c13
-rw-r--r--usr/src/lib/libfakekernel/common/mapfile-vers12
-rw-r--r--usr/src/lib/libfakekernel/common/printf.c29
-rw-r--r--usr/src/lib/libfakekernel/common/rwlock.c1
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cmn_err.h8
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cred.h5
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cyclic.h87
-rw-r--r--usr/src/lib/libfakekernel/common/uio.c4
-rw-r--r--usr/src/lib/libproc/common/libproc.h4
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers3
-rw-r--r--usr/src/lib/libproc/common/proc_names.c40
-rw-r--r--usr/src/lib/libshare/smbfs/libshare_smbfs.c39
-rw-r--r--usr/src/lib/libshare/smbfs/libshare_smbfs.h6
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com27
-rw-r--r--usr/src/lib/libsmbfs/cflib.h4
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h45
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_api.h7
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_api.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c650
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c246
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c51
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c7
-rw-r--r--usr/src/lib/libsmbfs/smb/getaddr.c17
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c96
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c6
-rw-r--r--usr/src/lib/libsmbfs/smb/krb5ssp.c61
-rw-r--r--usr/src/lib/libsmbfs/smb/lgrep.awk68
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers31
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_ssn.c336
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c457
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c47
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h20
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c113
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c33
-rw-r--r--usr/src/lib/libsmbfs/smb/private.h68
-rw-r--r--usr/src/lib/libsmbfs/smb/rap.c446
-rw-r--r--usr/src/lib/libsmbfs/smb/rc_scf.c231
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c86
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile_priv.h28
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c467
-rw-r--r--usr/src/lib/libsmbfs/smb/signing.c263
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c459
-rw-r--r--usr/src/lib/smbclnt/Makefile24
-rw-r--r--usr/src/lib/smbclnt/Makefile.lib51
-rw-r--r--usr/src/lib/smbclnt/Makefile.smbclnt66
-rw-r--r--usr/src/lib/smbclnt/Makefile.subdirs43
-rw-r--r--usr/src/lib/smbclnt/Makefile.targ50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile16
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile.com109
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/amd64/Makefile21
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c133
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c105
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c45
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c432
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c48
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c90
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c263
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c1377
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c160
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h314
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c163
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h45
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb19
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers134
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h67
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h183
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h70
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h65
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h141
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h622
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h116
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h1452
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/i386/Makefile18
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/sparc/Makefile18
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile23
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile16
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile.com139
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile23
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c432
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c96
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c173
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c108
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c195
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c124
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c340
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c123
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c203
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c96
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c91
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c2155
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c2026
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c76
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c235
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h73
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs19
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers68
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/i386/Makefile20
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile20
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile24
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.c8
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c4
-rw-r--r--usr/src/man/man3lib/libproc.3lib31
-rw-r--r--usr/src/man/man3proc/Makefile5
-rw-r--r--usr/src/man/man3proc/proc_fltname.3proc24
-rw-r--r--usr/src/man/man4/nsmbrc.435
-rw-r--r--usr/src/pkg/manifests/system-library.man3proc.inc3
-rwxr-xr-xusr/src/tools/quick/make-smbclnt45
-rw-r--r--usr/src/tools/scripts/wsdiff.py118
-rw-r--r--usr/src/uts/common/Makefile.files4
-rw-r--r--usr/src/uts/common/fs/fs_subr.h2
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple22
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov29
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c180
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/offsets.in85
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c382
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h44
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c253
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c1325
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c148
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h231
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c269
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c1597
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h39
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c322
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h50
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c171
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h73
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c810
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h105
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c349
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c215
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h20
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c262
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h3
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c622
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c54
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c36
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c49
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c3
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c2514
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c926
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c896
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c294
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h184
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c9
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c112
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c396
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c186
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dfs.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vss.c2
-rw-r--r--usr/src/uts/common/io/aac/aac.c10
-rw-r--r--usr/src/uts/common/netsmb/mchain.h25
-rw-r--r--usr/src/uts/common/netsmb/smb.h62
-rw-r--r--usr/src/uts/common/netsmb/smb2.h465
-rw-r--r--usr/src/uts/common/netsmb/smb_dev.h178
-rw-r--r--usr/src/uts/common/smb/Makefile4
-rw-r--r--usr/src/uts/common/smb/ntaccess.h (renamed from usr/src/uts/common/smbsrv/ntaccess.h)4
-rw-r--r--usr/src/uts/common/smb/winioctl.h (renamed from usr/src/uts/common/smbsrv/winioctl.h)8
-rw-r--r--usr/src/uts/common/smbsrv/Makefile4
-rw-r--r--usr/src/uts/common/smbsrv/smb.h4
-rw-r--r--usr/src/uts/common/sys/conf.h10
-rw-r--r--usr/src/uts/common/sys/debug.h4
-rw-r--r--usr/src/uts/common/sys/dirent.h2
-rw-r--r--usr/src/uts/common/sys/dnlc.h6
-rw-r--r--usr/src/uts/common/sys/file.h15
-rw-r--r--usr/src/uts/common/sys/model.h2
-rw-r--r--usr/src/uts/common/sys/modhash.h2
-rw-r--r--usr/src/uts/common/sys/poll.h2
-rw-r--r--usr/src/uts/common/sys/share.h2
-rw-r--r--usr/src/uts/common/sys/signal.h2
-rw-r--r--usr/src/uts/common/sys/stream.h6
-rw-r--r--usr/src/uts/common/sys/strsubr.h17
-rw-r--r--usr/src/uts/common/sys/t_kuser.h1
-rw-r--r--usr/src/uts/intel/nsmb/ioc_check.ref89
-rw-r--r--usr/src/uts/intel/pcbe/core_pcbe.c3
-rw-r--r--usr/src/uts/sparc/nsmb/ioc_check.ref89
226 files changed, 26864 insertions, 9311 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/Makefile b/usr/src/cmd/fs.d/smbclnt/Makefile
index 5e26c570b3..e6b660643f 100644
--- a/usr/src/cmd/fs.d/smbclnt/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile
@@ -20,8 +20,8 @@
#
#
-# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -33,7 +33,7 @@ include $(SRC)/Makefile.master
SUBDIRS_CATALOG= smbutil mount umount share
SUBDIRS= $(SUBDIRS_CATALOG) chacl lsacl \
- smbiod smbiod-svc svc test
+ smbiod smbiod-svc svc fksmbcl
# for messaging catalog files
#
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc b/usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc
new file mode 100644
index 0000000000..8c05f688c5
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc
@@ -0,0 +1,24 @@
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+# set -o emacs
+
+# fksmbcl is always 32-bit
+setenv LD_LIBRARY_PATH ${ROOT}/usr/lib/smbfs:${ROOT}/usr/lib:${ROOT}/lib
+
+echo 'Do one of: attach ${PID}'
+echo 'or: debug ${ROOT}/usr/lib/smbfs/fksmbcl'
+echo 'then: run -v //localhost'
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile
new file mode 100644
index 0000000000..5ae4f56e1b
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile
@@ -0,0 +1,104 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+PROG= fksmbcl
+
+OBJS_LOCAL = \
+ fksmbcl_main.o \
+ fkdev.o \
+ fknewvc.o \
+ fkiod_cl.o \
+ shares.o
+
+OBJS= ${OBJS_LOCAL}
+SRCS= ${OBJS_LOCAL:.o=.c}
+
+include ../../../Makefile.cmd
+include ../../../Makefile.ctf
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+# CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+INCS += -I$(SRC)/common/smbclnt
+INCS += -I$(SRC)/common
+
+# Allow cpp to find libfknsmb.h etc. via
+# include <libfknsmb/common/libfknsmb.h>
+INCS += -I$(SRC)/lib/smbclnt
+INCS += -I$(SRC)/lib/libsmbfs
+INCS += -I$(SRC)/lib/libsmbfs/netsmb
+
+CPPFLAGS += $(INCS)
+CPPFLAGS += -D_REENTRANT
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+CPPFLAGS += -D_LARGEFILE64_SOURCE=1
+CPPFLAGS += -DFKSMBCL
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CSTD= $(CSTD_GNU99)
+
+CFLAGS += $(CCVERBOSE)
+CFLAGS64 += $(CCVERBOSE)
+
+LDFLAGS += $(ZNOLAZYLOAD)
+LDFLAGS += -R/usr/lib/smbfs
+LDLIBS += -L$(ROOT)/usr/lib/smbfs
+LDLIBS += -lsmbfs -lfksmbfs -lfknsmb
+LDLIBS += -lsocket
+
+ROOTSMBDDIR = $(ROOTLIB)/smbfs
+ROOTSMBDFILE = $(PROG:%=$(ROOTSMBDDIR)/%)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ -$(RM) $(OBJS)
+
+# lots of lint due to mixing kernel+user stuff. give up.
+lint: # lint_SRCS
+
+include ../../../Makefile.targ
+
+install: all $(ROOTSMBDFILE)
+
+$(ROOTSMBDDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/README b/usr/src/cmd/fs.d/smbclnt/fksmbcl/README
new file mode 100644
index 0000000000..811401bc65
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/README
@@ -0,0 +1,99 @@
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+This directory builds a program linking all of the SMB client code
+into a user-level process. The result is not a fully functional
+SMB client but is very useful for some kinds of development work.
+
+The architecture of this roughly parallels the in-kernel version,
+where the kernel modules are built as libraries including:
+ libfksmbfs, libfknsmb
+
+Just as with the kernel code, there are mdb modules that know
+how to walk data structures in libfksmbfs, etc.
+
+For debugging, etc. it's easiest to run this as a normal user,
+i.e. yourself (not root)
+
+Now you can run fksmbcl from the proto area using this script:
+ ./Run.sh -df
+
+You can also run it under dbx (see the .dbxrc file).
+To run it under mdb (with mdb modules build here):
+ mdb -L $ROOT/usr/lib/mdb/proc:/usr/lib/mdb/proc ...
+where ... is one of: fksmbcl, core.nnn, -p $PID
+
+There are also some dtrace scripts in here, and in ../dtrace
+for watching either all activity or only selected areas.
+Run these like: dtrace -s Watch-all.d -p $PID -o output
+
+These two (from over in ../dtrace) also work with fksmbcl:
+ dtrace -s fksmbcl.d -p `pgrep fksmbcl` -o output
+
+Here is the help output:
+
+ > help
+ Commands:
+ help
+ exit
+ logon [user [dom [pass]]]
+ logoff [close-driver]
+ shares
+ mount {share} [optstr]
+ umount
+ unmount
+ statfs
+ dir {rdir} [lfile]
+ dirx {rdir} [lfile]
+ get {rfile} [lfile]
+ put {lfile} [rfile]
+ mv {from} {to}
+ rm {rfile}
+ mkdir {rfile}
+ rmdir {rfile}
+ opt {option}
+
+
+Here is an example of how to connect, mount, and list a directory:
+
+ $ ./Run.sh //myserver
+ # Start with:
+ > logon [user [dom [pw]]]
+ > shares
+ > mount {share}
+
+ > logon test test test
+ > shares
+ open pipe: /srvsvc
+ enum strings
+ junk
+ c$
+ Default Share
+ test1
+ ipc$
+ Remote IPC
+ test
+ > mount test
+ > dir
+ 1224750917 .
+ 1224750917 ..
+ 900818955 test9.dat
+ 3908265151 lock1.txt
+ 2452346625 test_dir
+ > umount
+ > logoff
+ > exit
+ $
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh
new file mode 100755
index 0000000000..df731bf733
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+# Helper program to run fksmbd (user-space smbd for debugging)
+# using binaries from the proto area.
+
+[ -n "$ROOT" ] || {
+ echo "Need a bldenv to set ROOT=..."
+ exit 1;
+}
+
+# OK, setup env. to run it.
+
+LD_LIBRARY_PATH=$ROOT/usr/lib/smbfs:$ROOT/usr/lib:$ROOT/lib
+export LD_LIBRARY_PATH
+
+# run with the passed options
+exec $ROOT/usr/lib/smbfs/fksmbcl "$@"
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
new file mode 100644
index 0000000000..b36fd13d6f
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
@@ -0,0 +1,68 @@
+#!/usr/sbin/dtrace -s
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * User-level dtrace for fksmbcl
+ * Usage: dtrace -s Watch-fksmbcl.d -p $PID
+ */
+
+/*
+ * If traced, print entry/return
+ */
+pid$target:fksmbcl::entry,
+pid$target:libsmbfs.so.1::entry,
+pid$target:libfksmbfs.so.1::entry,
+pid$target:libfknsmb.so.1::entry,
+pid$target:libfakekernel.so.1::entry
+{
+ printf("\t0x%x", arg0);
+ printf("\t0x%x", arg1);
+ printf("\t0x%x", arg2);
+ printf("\t0x%x", arg3);
+ printf("\t0x%x", arg4);
+ printf("\t0x%x", arg5);
+}
+
+pid$target:fksmbcl::return,
+pid$target:libsmbfs.so.1::return,
+pid$target:libfksmbfs.so.1::return,
+pid$target:libfknsmb.so.1::return,
+pid$target:libfakekernel.so.1::entry
+{
+ printf("\t0x%x", arg1);
+}
+
+pid$target::smbfslookup:entry
+{
+ printf("\tname = %s\n", copyinstr(arg1));
+}
+
+pid$target:libfknsmb.so.1:smb_dtrace2:entry
+/copyinstr(arg0) == "debugmsg2"/
+{
+ this->f = copyinstr(arg1);
+ this->m = copyinstr(arg2);
+ printf("\n\t debugmsg2: %s: %s ", this->f, this->m);
+}
+
+pid$target:libfknsmb.so.1:smb_dtrace3:entry
+/copyinstr(arg0) == "debugmsg3"/
+{
+ this->f = copyinstr(arg1);
+ this->m = copyinstr(arg2);
+ printf("\n\t debugmsg3: %s: %s ", this->f, this->m);
+ trace(arg3);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c
new file mode 100644
index 0000000000..34da749e78
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c
@@ -0,0 +1,98 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * This file implements device open/close/ioctl wrappers that
+ * redirect access from the real "nsmb" device to the in-process
+ * device simulation in libfknsmb.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/byteorder.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <assert.h>
+#include <nss_dbdefs.h>
+
+#include <cflib.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include <libfknsmb/common/libfknsmb.h>
+
+#include "smb/charsets.h"
+#include "smb/private.h"
+
+int
+smb_open_driver(void)
+{
+ dev32_t dev;
+ int fd;
+ int rc;
+
+ rc = nsmb_drv_open(&dev, 0, 0);
+ if (rc != 0) {
+ errno = rc;
+ return (-1);
+ }
+
+ assert((dev & 0xFFFF0000) != 0);
+ fd = (int)dev;
+
+ return (fd);
+}
+
+int
+nsmb_ioctl(int fd, int cmd, void *arg)
+{
+ dev32_t dev;
+ int err;
+
+ dev = (dev32_t)fd;
+ assert((dev & 0xFFFF0000) != 0);
+ err = nsmb_drv_ioctl(dev, cmd, (intptr_t)arg, 0);
+ if (err != 0) {
+ errno = err;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+nsmb_close(int fd)
+{
+ dev32_t dev;
+
+ dev = (dev32_t)fd;
+ assert((dev & 0xFFFF0000) != 0);
+ (void) nsmb_drv_close(dev, 0, 0);
+ return (0);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c
new file mode 100644
index 0000000000..be26854bd3
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c
@@ -0,0 +1,150 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Client-side interface to the IO Daemon (IOD)
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <thread.h>
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include <assert.h>
+
+#include "smb/charsets.h"
+#include "smb/private.h"
+
+/*
+ * Make sure we don't call the real IOD here.
+ */
+int
+smb_iod_open_door(int *fdp)
+{
+ *fdp = -1;
+ return (ENOTSUP);
+}
+
+/*
+ * Get a door handle to the IOD...
+ */
+int
+smb_iod_start(smb_ctx_t *ctx)
+{
+ return (0);
+}
+
+void *
+iod_work(void *arg)
+{
+ smb_ctx_t *ctx = arg;
+ (void) smb_iod_work(ctx);
+ smb_ctx_free(ctx);
+ return (NULL);
+}
+
+/*
+ * Ask the IOD to connect using the info in ctx.
+ * Called by newvc.
+ *
+ * This function largely follows smbiod.c : iod_newvc()
+ */
+int
+smb_iod_cl_newvc(smb_ctx_t *cl_ctx)
+{
+ smb_ctx_t *ctx;
+ thread_t tid;
+ int err = 0;
+
+ /*
+ * Clone the context, like in smbiod.c
+ */
+ err = smb_ctx_alloc(&ctx);
+ if (err)
+ return (err);
+ bcopy(&cl_ctx->ct_iod_ssn, &ctx->ct_iod_ssn,
+ sizeof (ctx->ct_iod_ssn));
+
+ /*
+ * Create the driver session first...
+ */
+ if ((err = smb_ctx_gethandle(ctx)) != 0)
+ goto out;
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
+ err = errno;
+ if (err == EEXIST)
+ err = 0; /* see above */
+ goto out;
+ }
+
+ /*
+ * Do the initial connection setup here, so we can
+ * report the outcome to the door client.
+ */
+ err = smb_iod_connect(ctx);
+ if (err != 0) {
+ fprintf(stderr, "smb_iod_connect, err=%d\n", err);
+ goto out;
+ }
+
+ /* The rest happens in the iod_work thread. */
+ err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
+ if (err == 0) {
+ /*
+ * Given to the new thread.
+ * free at end of iod_work
+ */
+ ctx = NULL;
+ }
+
+out:
+ if (ctx != NULL)
+ smb_ctx_free(ctx);
+
+ return (err);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c
new file mode 100644
index 0000000000..7f66b3b5bb
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c
@@ -0,0 +1,143 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Create a new VC given a list of addresses.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "smb/charsets.h"
+#include "smb/private.h"
+
+/*
+ * Ask the IOD to create a VC with this IP address.
+ */
+static int
+fknewvc(struct smb_ctx *ctx, struct addrinfo *ai)
+{
+ char host[256];
+ char svc[32];
+ smbioc_ossn_t *ssn = &ctx->ct_ssn;
+ int err;
+
+ if (smb_debug) {
+ err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ host, sizeof (host), svc, sizeof (svc),
+ AI_NUMERICHOST);
+ if (err != 0) {
+ strlcpy(host, "(?)", sizeof (host));
+ strlcpy(svc, "?", sizeof (host));
+ }
+ printf("fknewvc: Try AF=%d %s:%s\n",
+ ai->ai_family, host, svc);
+ }
+
+ /*
+ * Copy the passed address into ssn_srvaddr,
+ * but first sanity-check lengths. Also,
+ * zero it first to avoid trailing junk.
+ */
+ if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr))
+ return (EINVAL);
+ bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
+ bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
+
+ /* Ask the IOD to connect using the info in ctx. */
+ err = smb_iod_cl_newvc(ctx);
+ if (smb_debug) {
+ printf("fknewvc: iod_cl_newvc err=%d\n", err);
+ }
+
+ return (err);
+}
+
+/*
+ * Setup a new VC via the IOD.
+ * Similar to findvc.c
+ */
+int
+smb_ctx_newvc(struct smb_ctx *ctx)
+{
+ struct addrinfo *ai;
+ int err;
+
+ /* Should already have the address list. */
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+ return (EINVAL);
+
+ err = EPROTONOSUPPORT; /* in case no AF match */
+ for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
+
+ switch (ai->ai_family) {
+
+ case AF_INET:
+ case AF_INET6:
+ case AF_NETBIOS:
+ err = fknewvc(ctx, ai);
+ if (err == 0)
+ return (0);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * In the error case, the caller may try again
+ * with new auth. info, so keep the door open.
+ * Error return will close in smb_ctx_done.
+ */
+ return (err);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
new file mode 100644
index 0000000000..8b1757ea62
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
@@ -0,0 +1,938 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Test & debug program for the SMB client
+ *
+ * This implements a simple command reader which accepts
+ * commands to simulate system calls into the file system.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/dirent.h>
+#include <sys/strlog.h> /* SL_NOTE */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <sys/fs/smbfs_mount.h>
+#include <netsmb/smb_lib.h>
+#include <libfknsmb/common/libfknsmb.h>
+#include <libfksmbfs/common/libfksmbfs.h>
+
+#if _FILE_OFFSET_BITS != 64
+#error "This calls (fake) VFS code which requires 64-bit off_t"
+#endif
+
+extern int list_shares(struct smb_ctx *);
+
+#define MAXARG 10
+
+struct cmd_tbl_ent {
+ void (*ce_func)(int, char **);
+ const char *ce_name;
+ const char *ce_argdesc;
+};
+static struct cmd_tbl_ent cmd_tbl[];
+
+static struct smb_ctx *ctx = NULL;
+static char *server = NULL;
+
+static vfs_t *vfsp = NULL;
+
+static void show_dents(vnode_t *, offset_t *, char *, int);
+static void run_cli(void);
+
+#define TBUFSZ 8192
+static char tbuf[TBUFSZ];
+
+static void
+fksmbcl_usage(void)
+{
+ printf("usage: fksmbcl //user@server (like smbutil)\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int error, opt;
+
+ /*
+ * Initializations
+ */
+ nsmb_drv_load();
+ nsmb_drv_init();
+ fksmbfs_init();
+
+ while ((opt = getopt(argc, argv, "dv")) != -1) {
+ switch (opt) {
+ case 'd':
+ smb_debug++;
+ break;
+ case 'v':
+ smb_verbose++;
+ break;
+ case '?':
+ fksmbcl_usage();
+ break;
+ }
+ }
+ if (optind >= argc)
+ fksmbcl_usage();
+ server = argv[optind];
+
+ /*
+ * Setup the libsmbfs context
+ */
+ error = smb_ctx_alloc(&ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_alloc failed (%d)\n",
+ argv[0], error);
+ return (1);
+ }
+
+ error = smb_ctx_scan_argv(ctx, argc, argv,
+ SMBL_SERVER, SMBL_SERVER, USE_WILDCARD);
+ if (error) {
+ fprintf(stderr, "logon: smb_ctx_scan_argv, error %d\n", error);
+ return (1);
+ }
+ error = smb_ctx_readrc(ctx);
+ if (error) {
+ fprintf(stderr, "logon: smb_ctx_readrc, error %d\n", error);
+ return (1);
+ }
+
+ /* Do smb_ctx_setshare later, and smb_ctx_resolve. */
+
+ /*
+ * Next would be smb_ctx_get_ssn() but don't do that until
+ * the "logon" command so one can set breakpoints etc.
+ */
+
+ /*
+ * Run the CLI
+ */
+ run_cli();
+
+ /*
+ * Cleanup
+ */
+ fksmbfs_fini();
+ nsmb_drv_fini();
+
+ return (0);
+}
+
+static void
+run_cli()
+{
+ static char cmdbuf[100];
+ int argc, i;
+ char *argv[MAXARG];
+ char *cmd;
+ char *savep = NULL;
+ char *sep = " \t\n";
+ char *prompt = NULL;
+ struct cmd_tbl_ent *ce;
+
+ if (isatty(0)) {
+ fputs("# Start with:\n"
+ "> logon [user [dom [pw]]]\n"
+ "> shares\n"
+ "> mount {share}\n\n",
+ stdout);
+ prompt = "> ";
+ }
+
+ for (;;) {
+ if (prompt) {
+ fputs(prompt, stdout);
+ fflush(stdout);
+ }
+
+ cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin);
+ if (cmd == NULL)
+ break;
+ if (cmd[0] == '#')
+ continue;
+
+ if (prompt == NULL) {
+ /* Put commands in the output too. */
+ fprintf(stdout, "+ %s", cmdbuf);
+ }
+
+ argv[0] = strtok_r(cmd, sep, &savep);
+ if (argv[0] == NULL)
+ continue;
+ for (argc = 1; argc < MAXARG; argc++) {
+ argv[argc] = strtok_r(NULL, sep, &savep);
+ if (argv[argc] == NULL)
+ break;
+ }
+ for (i = argc; i < MAXARG; i++)
+ argv[i++] = NULL;
+
+ for (ce = cmd_tbl; ce->ce_name != NULL; ce++)
+ if (strcmp(ce->ce_name, argv[0]) == 0)
+ break;
+ if (ce->ce_name != NULL) {
+ ce->ce_func(argc, argv);
+ } else {
+ fprintf(stderr, "%s unknown command. Try help\n",
+ argv[0]);
+ }
+ }
+}
+
+/*
+ * Command handlers
+ */
+
+static void
+do_exit(int argc, char **argv)
+{
+ exit(0);
+}
+
+static void
+do_help(int argc, char **argv)
+{
+ struct cmd_tbl_ent *ce;
+
+ printf("Commands:\n");
+ for (ce = cmd_tbl; ce->ce_func != NULL; ce++)
+ printf("%s %s\n", ce->ce_name, ce->ce_argdesc);
+}
+
+static void
+do_logon(int argc, char **argv)
+{
+ int error;
+
+ if (argc > 1) {
+ if (argv[1][0] == '-') {
+ smb_ctx_setuser(ctx, "", B_TRUE);
+ ctx->ct_flags |= SMBCF_NOPWD;
+ } else {
+ smb_ctx_setuser(ctx, argv[1], B_TRUE);
+ }
+ }
+ if (argc > 2)
+ smb_ctx_setdomain(ctx, argv[2], B_TRUE);
+ if (argc > 3)
+ smb_ctx_setpassword(ctx, argv[3], NULL);
+
+ /*
+ * Resolve the server address, setup derived defaults.
+ */
+ error = smb_ctx_resolve(ctx);
+ if (error) {
+ fprintf(stderr, "logon: smb_ctx_resolve, error %d\n", error);
+ return;
+ }
+
+ /*
+ * Have server, share, etc. now.
+ * Get the logon session.
+ */
+again:
+ error = smb_ctx_get_ssn(ctx);
+ if (error == EAUTH) {
+ int err2;
+ err2 = smb_get_authentication(ctx);
+ if (err2 == 0)
+ goto again;
+ }
+ if (error) {
+ fprintf(stderr, "//%s: login failed, error %d\n",
+ ctx->ct_fullserver, error);
+ }
+}
+
+/*
+ * Drop session created by the "logon" command.
+ */
+static void
+do_logoff(int argc, char **argv)
+{
+
+ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_RELE, NULL);
+ if (argc > 1) {
+ smb_ctx_done(ctx);
+ (void) smb_ctx_init(ctx);
+ }
+}
+
+/*
+ * List shares
+ */
+static void
+do_shares(int argc, char **argv)
+{
+ int error;
+
+ smb_ctx_setshare(ctx, "IPC$", USE_IPC);
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ fprintf(stderr, "shares, tcon IPC$, error=%d\n", error);
+ return;
+ }
+
+ error = list_shares(ctx);
+ if (error) {
+ fprintf(stderr, "shares, enum, error=%d\n", error);
+ }
+
+ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL);
+}
+
+char mnt_opt_buf[MAX_MNTOPT_STR];
+char mnt_resource[MAXPATHLEN];
+
+/*
+ * Minimal excerpt from vfs.c:domount()
+ */
+void
+do_mount(int argc, char **argv)
+{
+ struct smbfs_args mdata;
+ struct mounta ma;
+ char *shrname;
+ int error;
+
+ if (vfsp != NULL) {
+ fprintf(stderr, "Already mounted\n");
+ return;
+ }
+
+ if (argc < 2) {
+ fprintf(stderr, "%s: missing share name\n", argv[0]);
+ return;
+ }
+ shrname = argv[1];
+ if (argc > 2)
+ strlcpy(mnt_opt_buf, argv[2], sizeof (mnt_opt_buf));
+ else
+ memset(mnt_opt_buf, 0, sizeof (mnt_opt_buf));
+
+ smb_ctx_setshare(ctx, shrname, USE_DISKDEV);
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
+ server, shrname, error);
+ return;
+ }
+
+ (void) snprintf(mnt_resource, sizeof (mnt_resource),
+ "//%s/%s", ctx->ct_fullserver, shrname);
+
+ bzero(&mdata, sizeof (mdata));
+ mdata.version = SMBFS_VERSION; /* smbfs mount version */
+ mdata.file_mode = S_IRWXU;
+ mdata.dir_mode = S_IRWXU;
+ mdata.devfd = ctx->ct_dev_fd;
+
+ /* Build mount args */
+ bzero(&ma, sizeof (ma));
+ ma.spec = mnt_resource;
+ ma.dir = "/";
+ ma.flags = MS_DATA | MS_OPTIONSTR | MS_NOSPLICE | MS_NOSUID;
+ ma.fstype = "smbfs";
+ ma.dataptr = (void *) &mdata;
+ ma.datalen = sizeof (mdata);
+ ma.optptr = mnt_opt_buf;
+ ma.optlen = sizeof (mnt_opt_buf);
+
+ error = fake_domount("smbfs", &ma, &vfsp);
+ if (error != 0) {
+ fprintf(stderr, "domount error=%d\n", error);
+ }
+
+ /* Mount takes a ref, so always rele here. */
+ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL);
+}
+
+void
+do_unmount(int argc, char **argv)
+{
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "Not mounted\n");
+ return;
+ }
+
+ error = fake_dounmount(vfsp, 0);
+ if (error != 0) {
+ fprintf(stderr, "dounmount error=%d\n", error);
+ return;
+ }
+ vfsp = NULL;
+}
+
+void
+do_statfs(int argc, char **argv)
+{
+ statvfs64_t st;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "Not mounted\n");
+ return;
+ }
+
+ error = fsop_statfs(vfsp, &st);
+ if (error != 0) {
+ fprintf(stderr, "df error=%d\n", error);
+ return;
+ }
+ printf("bsize=%ld\n", st.f_bsize);
+ printf("frsize=%ld\n", st.f_frsize);
+ printf("blocks=%" PRIu64 "\n", st.f_blocks);
+ printf(" bfree=%" PRIu64 "\n", st.f_bfree);
+ printf("bavail=%" PRIu64 "\n", st.f_bavail);
+}
+
+void
+do_dir(int argc, char **argv)
+{
+ char *rdir;
+ vnode_t *vp = NULL;
+ offset_t off;
+ int cnt;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc > 1)
+ rdir = argv[1];
+ else
+ rdir = "";
+
+ error = vn_open(rdir, 0, FREAD, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_dir, vn_open error=%d\n", error);
+ return;
+ }
+
+ off = 0;
+ do {
+ cnt = fake_getdents(vp, &off, tbuf, TBUFSZ);
+ if (cnt < 0) {
+ fprintf(stderr, "do_dir, getdents %d\n", -cnt);
+ break;
+ }
+ show_dents(vp, &off, tbuf, cnt);
+ } while (cnt > 0);
+
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+}
+
+void
+do_dirx(int argc, char **argv)
+{
+ char *rdir;
+ vnode_t *vp = NULL;
+ offset_t off;
+ int cnt;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc > 1)
+ rdir = argv[1];
+ else
+ rdir = "";
+
+ error = vn_open(rdir, 0, FREAD|FXATTRDIROPEN, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_dirx, vn_open error=%d\n", error);
+ return;
+ }
+
+ off = 0;
+ do {
+ cnt = fake_getdents(vp, &off, tbuf, TBUFSZ);
+ if (cnt < 0) {
+ fprintf(stderr, "do_dirx, getdents %d\n", -cnt);
+ break;
+ }
+ show_dents(vp, &off, tbuf, cnt);
+ } while (cnt > 0);
+
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+}
+
+static void
+show_dents(vnode_t *dvp, offset_t *offp, char *buf, int cnt)
+{
+ char time_buf[40];
+ struct stat64 st;
+ vnode_t *vp;
+ char *p;
+ dirent_t *d;
+ offset_t offset = (offset_t)-1L;
+ int error;
+ uint_t mode;
+ char type;
+
+ p = buf;
+ while (p < (buf + cnt)) {
+ d = (dirent_t *)(void *)p;
+ p += d->d_reclen;
+ offset = d->d_off;
+
+ error = fake_lookup(dvp, d->d_name, &vp);
+ if (error != 0) {
+ fprintf(stderr, "%s: lookup error=%d\n",
+ d->d_name, error);
+ continue;
+ }
+ error = fake_stat(vp, &st, 0);
+ vn_rele(vp);
+ if (error != 0) {
+ fprintf(stderr, "%s: stat error=%d\n",
+ d->d_name, error);
+ continue;
+ }
+
+ /*
+ * Print type, mode, size, name
+ * First mode (only dir, file expected here)
+ */
+ if (S_ISDIR(st.st_mode)) {
+ type = 'd';
+ } else if (S_ISREG(st.st_mode)) {
+ type = ' ';
+ } else {
+ type = '?';
+ }
+ mode = st.st_mode & 0777;
+ (void) strftime(time_buf, sizeof (time_buf),
+ "%b %e %T %Y", localtime(&st.st_mtime));
+
+ printf("%c 0%3o %9" PRIu64 " %s %s\n",
+ type, mode,
+ (uint64_t)st.st_size,
+ time_buf,
+ d->d_name);
+ }
+ *offp = offset;
+}
+
+/*
+ * get rname [lname]
+ */
+void
+do_get(int argc, char **argv)
+{
+ struct stat64 st;
+ char *rname;
+ char *lname;
+ vnode_t *vp = NULL;
+ offset_t off;
+ ssize_t cnt, x;
+ int oflg = O_RDWR | O_CREAT;
+ int lfd = -1;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+ if (argc > 2) {
+ lname = argv[2];
+ /*
+ * When local name is specified, overwrite.
+ * Convenient for scripts etc.
+ */
+ oflg |= O_TRUNC;
+ } else {
+ lname = rname;
+ /* Local file should not exist. */
+ oflg |= O_EXCL;
+ }
+
+ lfd = open(lname, oflg, 0644);
+ if (lfd < 0) {
+ perror(lname);
+ return;
+ }
+
+ error = vn_open(rname, 0, FREAD, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_get, vn_open error=%d\n", error);
+ goto out;
+ }
+ error = fake_stat(vp, &st, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_get, stat error=%d\n", error);
+ goto out;
+ }
+
+ off = 0;
+ do {
+ cnt = fake_pread(vp, tbuf, TBUFSZ, off);
+ if (cnt < 0) {
+ fprintf(stderr, "do_get, read %d\n", -cnt);
+ goto out;
+ }
+ x = write(lfd, tbuf, cnt);
+ if (x < 0) {
+ fprintf(stderr, "do_get, write %d\n", errno);
+ goto out;
+ }
+ off += x;
+ } while (off < st.st_size);
+
+out:
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+ if (lfd != -1)
+ close(lfd);
+}
+
+/*
+ * put lname [rname]
+ */
+void
+do_put(int argc, char **argv)
+{
+ struct stat64 rst;
+ struct stat st;
+ char *rname;
+ char *lname;
+ vnode_t *vp = NULL;
+ offset_t off;
+ ssize_t cnt, x;
+ int oflg = FREAD|FWRITE|FCREAT;
+ int lfd = -1;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "lname required\n");
+ return;
+ }
+ lname = argv[1];
+ if (argc > 2) {
+ rname = argv[2];
+ /*
+ * When remote name is specified, overwrite.
+ * Convenient for scripts etc.
+ */
+ oflg |= FTRUNC;
+ } else {
+ rname = lname;
+ /* Remote file should not exist. */
+ oflg |= FEXCL;
+ }
+
+ lfd = open(lname, O_RDONLY, 0);
+ if (lfd < 0) {
+ perror(lname);
+ return;
+ }
+ error = fstat(lfd, &st);
+ if (error != 0) {
+ fprintf(stderr, "do_put, stat error=%d\n", error);
+ goto out;
+ }
+
+ error = vn_open(rname, 0, oflg, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_put, vn_open error=%d\n", error);
+ goto out;
+ }
+
+ off = 0;
+ do {
+ cnt = pread(lfd, tbuf, TBUFSZ, off);
+ if (cnt < 0) {
+ fprintf(stderr, "do_put, read %d\n", errno);
+ goto out;
+ }
+ x = fake_pwrite(vp, tbuf, cnt, off);
+ if (x < 0) {
+ fprintf(stderr, "do_put, write %d\n", -x);
+ goto out;
+ }
+ off += cnt;
+ } while (off < st.st_size);
+
+ /* This getattr should go OtW. */
+ error = fake_stat(vp, &rst, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_put, stat error=%d\n", error);
+ goto out;
+ }
+ if (rst.st_size != st.st_size) {
+ fprintf(stderr, "do_put, wrong size?\n");
+ }
+
+out:
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+ if (lfd != -1)
+ close(lfd);
+}
+
+/*
+ * rm rname
+ */
+void
+do_rm(int argc, char **argv)
+{
+ char *rname;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+
+ error = fake_unlink(rname, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_rm, unlink error=%d\n", error);
+ }
+}
+
+/*
+ * mv fromname toname
+ */
+void
+do_mv(int argc, char **argv)
+{
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 3) {
+ fprintf(stderr, "from_name to_name required\n");
+ return;
+ }
+
+ error = fake_rename(argv[1], argv[2]);
+ if (error != 0) {
+ fprintf(stderr, "do_mv, rename error=%d\n", error);
+ }
+}
+
+/*
+ * mkdir rname
+ */
+void
+do_mkdir(int argc, char **argv)
+{
+ char *rname;
+ vnode_t *vp = NULL;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+
+ error = vn_open(rname, 0, FCREAT, 0, &vp, CRMKDIR, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_mkdir, vn_open error=%d\n", error);
+ }
+
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+}
+
+/*
+ * rmdir rname
+ */
+void
+do_rmdir(int argc, char **argv)
+{
+ char *rname;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+
+ error = fake_unlink(rname, AT_REMOVEDIR);
+ if (error != 0) {
+ fprintf(stderr, "do_rmdir, unlink error=%d\n", error);
+ }
+}
+
+/*
+ * Simple option setting
+ *
+ * Each arg is handled as one line in .nsmbrc [default]
+ */
+void
+do_opt(int argc, char **argv)
+{
+ static char template[20] = "/tmp/fksmbclXXXXXX";
+ static char rcname[30];
+ char *tdname;
+ char *save_home;
+ FILE *fp;
+ int err, i;
+
+ if (argc < 2) {
+ fprintf(stderr, "opt {key}[=value]\n");
+ return;
+ }
+
+ tdname = mkdtemp(template);
+ if (tdname == NULL) {
+ perror("mkdtemp");
+ return;
+ }
+ (void) snprintf(rcname, sizeof (rcname),
+ "%s/.nsmbrc", tdname);
+
+ fp = fopen(rcname, "w");
+ if (fp == NULL) {
+ perror(rcname);
+ goto out;
+ }
+ fprintf(fp, "[default]\n");
+ for (i = 1; i < argc; i++)
+ fprintf(fp, "%s\n", argv[i]);
+ fclose(fp);
+
+ save_home = ctx->ct_home;
+ ctx->ct_home = tdname;
+ err = smb_ctx_readrc(ctx);
+ ctx->ct_home = save_home;
+
+ if (err != 0)
+ fprintf(stderr, "readrc, err=%d\n", err);
+
+out:
+ (void) unlink(rcname);
+ (void) rmdir(tdname);
+}
+
+/*
+ * Command table
+ */
+static struct cmd_tbl_ent
+cmd_tbl[] = {
+ { do_help, "help", "" },
+ { do_exit, "exit", "" },
+ { do_logon, "logon", "[user [dom [pass]]]" },
+ { do_logoff, "logoff", "[close-driver]" },
+ { do_shares, "shares", "" },
+ { do_mount, "mount", "{share} [optstr]" },
+ { do_unmount, "umount", "" },
+ { do_unmount, "unmount", "" },
+ { do_statfs, "statfs", "" },
+ { do_dir, "dir", "{rdir} [lfile]" },
+ { do_dirx, "dirx", "{rdir} [lfile]" },
+ { do_get, "get", "{rfile} [lfile]" },
+ { do_put, "put", "{lfile} [rfile]" },
+ { do_mv, "mv", "{from} {to}" },
+ { do_rm, "rm", "{rfile}" },
+ { do_mkdir, "mkdir", "{rfile}" },
+ { do_rmdir, "rmdir", "{rfile}" },
+ { do_opt, "opt", "{option}" },
+ { NULL, NULL, NULL }
+};
+
+/*
+ * Provide a real function (one that prints something) to replace
+ * the stub in libfakekernel. This prints cmn_err() messages.
+ */
+void
+fakekernel_putlog(char *msg, size_t len, int flags)
+{
+
+ /*
+ * [CE_CONT, CE_NOTE, CE_WARN, CE_PANIC] maps to
+ * [SL_NOTE, SL_NOTE, SL_WARN, SL_FATAL]
+ */
+ if (smb_debug == 0 && (flags & SL_NOTE))
+ return;
+ (void) fwrite(msg, 1, len, stdout);
+ (void) fflush(stdout);
+}
+
+/*
+ * Print nsmb debug messages via driver smb_debugmsg()
+ */
+void
+smb_debugmsg(const char *func, char *msg)
+{
+ if (smb_debug < 2)
+ return;
+ printf("[kmod] %s: %s\n", func, msg);
+}
+
+/*
+ * Enable libumem debugging
+ */
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/test/srvenum.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/shares.c
index ee3aeba014..2d8d0cf6da 100644
--- a/usr/src/cmd/fs.d/smbclnt/test/srvenum.c
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/shares.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -36,27 +36,17 @@
#include <string.h>
#include <unistd.h>
#include <libintl.h>
+#include <ctype.h>
-#include <netsmb/smbfs_api.h>
+#include <netsmb/smb_lib.h>
/*
* This is a quick hack for testing client-side named pipes.
- * Its purpose is to test the ability to connect to a server,
- * open a pipe, send and receive data. The "hack" aspect is
- * the use of hand-crafted RPC messages, which allows testing
- * of the named pipe API separately from the RPC libraries.
- *
- * I captured the two small name pipe messages sent when
- * requesting a share list via RPC over /pipe/srvsvc and
- * dropped them into the arrays below (bind and enum).
- * This program sends the two messages (with adjustments)
- * and just dumps whatever comes back over the pipe.
- * Use wireshark if you want to see decoded messages.
+ * Its purpose is to test SMB named-pipe interface separately
+ * from the RPC implementation. It's a "hack" because it uses
+ * hand-crafted RPC messages (extracted from network traffic).
*/
-extern char *optarg;
-extern int optind, opterr, optopt;
-
/* This is a DCE/RPC bind call for "srvsvc". */
static const uchar_t
srvsvc_bind[] = {
@@ -95,175 +85,35 @@ srvsvc_enum2[] = {
static uchar_t sendbuf[1024];
static uchar_t recvbuf[4096];
-static char *server;
-
-static int pipetest(struct smb_ctx *);
+/*
+ * Print strings found in the buffer.
+ */
static void
-srvenum_usage(void)
+pstrings(const uchar_t *buf, int len)
{
- printf("usage: srvenum [-d domain][-u user][-p passwd] server\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c, error;
- struct smb_ctx *ctx = NULL;
- char *dom = NULL;
- char *usr = NULL;
- char *pw = NULL;
-
- while ((c = getopt(argc, argv, "vd:u:p:")) != -1) {
- switch (c) {
- case 'v':
- smb_verbose = 1;
- break;
-
- case 'd':
- dom = optarg;
- break;
- case 'u':
- usr = optarg;
- break;
- case 'p':
- pw = optarg;
- break;
- case '?':
- srvenum_usage();
- break;
+ const uchar_t *p = buf;
+ uint16_t u2;
+ boolean_t instr = B_FALSE;
+
+ while (len > 2) {
+ u2 = *p++;
+ u2 |= (*p++) << 8;
+ len -= 2;
+
+ if ((u2 & 0xFF80) == 0 && isprint(u2)) {
+ /* printable */
+ instr = B_TRUE;
+ putchar(u2);
+ } else {
+ /* not printalbe */
+ if (instr)
+ putchar('\n');
+ instr = B_FALSE;
}
}
- if (optind >= argc)
- srvenum_usage();
- server = argv[optind];
-
- if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
- argv[0]);
- srvenum_usage();
- }
-
- /*
- * This section is intended to demonstrate how an
- * RPC client library might use this interface.
- */
- error = smb_ctx_alloc(&ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Set server, share, domain, user
- * (in the ctx handle).
- */
- smb_ctx_setfullserver(ctx, server);
- smb_ctx_setshare(ctx, "IPC$", USE_IPC);
- if (dom)
- smb_ctx_setdomain(ctx, dom, B_TRUE);
- if (usr)
- smb_ctx_setuser(ctx, usr, B_TRUE);
- if (pw)
- smb_ctx_setpassword(ctx, pw, NULL);
-
-
- /*
- * If this code were in smbutil or mount_smbfs, it would
- * get system and $HOME/.nsmbrc settings here, like this:
- */
-#if 0
- error = smb_ctx_readrc(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_readrc failed\n", argv[0]);
- goto out;
- }
-#endif
-
- /*
- * Resolve the server address,
- * setup derived defaults.
- */
- error = smb_ctx_resolve(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Get the session and tree.
- */
- error = smb_ctx_get_ssn(ctx);
- if (error) {
- fprintf(stderr, "//%s: login failed, error %d\n",
- server, error);
- goto out;
- }
- error = smb_ctx_get_tree(ctx);
- if (error) {
- fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
- server, "IPC$", error);
- goto out;
- }
-
- /*
- * Do some named pipe I/O.
- */
- error = pipetest(ctx);
- if (error) {
- fprintf(stderr, "pipetest, %d\n", error);
- goto out;
- }
-
-out:
- smb_ctx_free(ctx);
-
- return ((error) ? 1 : 0);
-}
-
-static void
-hexdump(const uchar_t *buf, int len) {
- int idx;
- char ascii[24];
- char *pa = ascii;
-
- memset(ascii, '\0', sizeof (ascii));
-
- idx = 0;
- while (len--) {
- if ((idx & 15) == 0) {
- printf("[%04X] ", idx);
- pa = ascii;
- }
- if (*buf > ' ' && *buf <= '~')
- *pa++ = *buf;
- else
- *pa++ = '.';
- printf("%02x ", *buf++);
-
- idx++;
- if ((idx & 7) == 0) {
- *pa++ = ' ';
- putchar(' ');
- }
- if ((idx & 15) == 0) {
- *pa = '\0';
- printf("%s\n", ascii);
- }
- }
-
- if ((idx & 15) != 0) {
- *pa = '\0';
- /* column align the last ascii row */
- do {
- printf(" ");
- idx++;
- if ((idx & 7) == 0)
- putchar(' ');
- } while ((idx & 15) != 0);
- printf("%s\n", ascii);
- }
+ if (instr)
+ putchar('\n');
}
/*
@@ -309,10 +159,6 @@ do_bind(int fid)
printf("xact bind, err=%d\n", err);
return (err);
}
- if (smb_verbose) {
- printf("bind ack, len=%d\n", len);
- hexdump(recvbuf, len);
- }
if (more > 0) {
if (more > sizeof (recvbuf)) {
printf("bogus more=%d\n", more);
@@ -325,17 +171,13 @@ do_bind(int fid)
printf("read enum resp, err=%d\n", err);
return (err);
}
- if (smb_verbose) {
- printf("bind ack (more), len=%d\n", len);
- hexdump(recvbuf, len);
- }
}
return (0);
}
static int
-do_enum(int fid)
+do_enum(char *server, int fid)
{
int err, len, rlen, wlen;
uchar_t *p;
@@ -393,18 +235,22 @@ do_enum(int fid)
return (err);
}
- /* Just dump the response data. */
- printf("enum recv, len=%d\n", rlen);
- hexdump(recvbuf, rlen);
+ /*
+ * Just dump strings found in the response data.
+ * Skip the first 0x90 (RPC wrappers).
+ */
+ printf("enum strings\n");
+ pstrings(recvbuf + 0x90, rlen - 0x90);
return (0);
}
-static int
-pipetest(struct smb_ctx *ctx)
+int
+list_shares(struct smb_ctx *ctx)
{
static char path[] = "/srvsvc";
static uchar_t key[16];
+ char *server = ctx->ct_srvname;
int err, fd;
printf("open pipe: %s\n", path);
@@ -426,7 +272,7 @@ pipetest(struct smb_ctx *ctx)
printf("do_bind: %d\n", err);
goto out;
}
- err = do_enum(fd);
+ err = do_enum(server, fd);
if (err)
printf("do_enum: %d\n", err);
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
index ae9dd15817..3a852c6978 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
@@ -23,7 +23,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 2018, Joyent, Inc.
#
@@ -34,7 +34,7 @@
PROG= smbutil
OBJS= smbutil.o discon.o info.o login.o lookup.o print.o status.o view.o \
- shares_rap.o shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o
+ shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o
SRCS= $(OBJS:%.o=%.c)
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c b/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c
deleted file mode 100644
index f2235e2880..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2000-2002, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: Id: view.c,v 1.9 2002/02/20 09:26:42 bp Exp
- */
-
-/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <netsmb/mchain.h> /* letohs, etc. */
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-
-#include "common.h"
-
-/*
- * Enumerate shares using Remote Administration Protocol (RAP)
- * Was in libsmbfs netshareenum.c
- */
-
-struct smb_share_info_1 {
- char shi1_netname[13];
- char shi1_pad;
- uint16_t shi1_type;
- uint32_t shi1_remark; /* char * */
-};
-
-static int
-smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
- int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
-{
- struct smb_rap *rap;
- long lval = -1;
- int error;
-
- error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
- if (error)
- return (error);
- smb_rap_setNparam(rap, sLevel); /* W - sLevel */
- smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */
- smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */
- error = smb_rap_request(rap, ctx);
- if (error == 0) {
- *pcEntriesRead = rap->r_entries;
- error = smb_rap_getNparam(rap, &lval);
- *pcTotalAvail = lval;
- /* Copy the data length into the IN/OUT variable. */
- *cbBuffer = rap->r_rcvbuflen;
- }
- error = smb_rap_error(rap, error);
- smb_rap_done(rap);
- return (error);
-}
-
-int
-share_enum_rap(smb_ctx_t *ctx)
-{
- struct smb_share_info_1 *shi;
- void *rpbuf;
- char *cp;
- int error, bufsize, i, rcnt, total;
- int lbound, rbound;
- uint16_t type;
-
- bufsize = 0xffe0; /* samba notes win2k bug for 65535 */
- rpbuf = malloc(bufsize);
- if (rpbuf == NULL)
- return (errno);
-
- error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &rcnt, &total);
- if (error &&
- error != (ERROR_MORE_DATA | SMB_RAP_ERROR))
- goto out;
-
- /*
- * Bounds for offsets to comments strings.
- * After the array, and before the end.
- */
- lbound = rcnt * (sizeof (struct smb_share_info_1));
- rbound = bufsize;
-
- /* Print the header line. */
- view_print_share(NULL, 0, NULL);
-
- for (shi = rpbuf, i = 0; i < rcnt; i++, shi++) {
- type = letohs(shi->shi1_type);
-
- shi->shi1_pad = '\0'; /* ensure null termination */
-
- /*
- * Offsets to comment strings can be trash.
- * Only print when the offset is valid.
- */
- if (shi->shi1_remark >= lbound &&
- shi->shi1_remark < rbound) {
- cp = (char *)rpbuf + shi->shi1_remark;
- } else
- cp = NULL;
-
- /* Convert from OEM to local codeset? */
- view_print_share(shi->shi1_netname, type, cp);
- }
- error = 0;
-
-out:
- free(rpbuf);
- return (error);
-}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
index bf3397c166..18f0488ad3 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -51,8 +51,6 @@
#include <netsmb/smb_lib.h>
#include "common.h"
-static int use_rap;
-
void
view_usage(void)
{
@@ -86,15 +84,6 @@ cmd_view(int argc, char *argv[])
while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
if (opt == '?')
view_usage();
- /*
- * This is an undocumented option, just for testing.
- * Use the old LanMan Remote API Protocol (RAP) for
- * enumerating shares.
- */
- if (opt == 'B') {
- use_rap++;
- continue;
- }
error = smb_ctx_opt(ctx, opt, optarg);
if (error)
goto out;
@@ -137,12 +126,8 @@ again:
/*
* Have IPC$ tcon, now list shares.
- * Try RPC; if that fails, do RAP.
*/
- if (!use_rap)
- error = share_enum_rpc(ctx, ctx->ct_fullserver);
- if (error || use_rap)
- error = share_enum_rap(ctx);
+ error = share_enum_rpc(ctx, ctx->ct_fullserver);
out:
smb_ctx_free(ctx);
diff --git a/usr/src/cmd/fs.d/smbclnt/test/Makefile b/usr/src/cmd/fs.d/smbclnt/test/Makefile
deleted file mode 100644
index affd6d9a00..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/test/Makefile
+++ /dev/null
@@ -1,85 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
-# Copyright (c) 2019, Joyent, Inc.
-#
-
-include $(SRC)/cmd/Makefile.cmd
-
-PROG= srvenum srvinfo tconn
-OBJS = $(PROG:%=%.o)
-SRCS = $(OBJS:%.o=%.c)
-
-# ROOTFS_PROG= $(LIBPROG)
-# include ../../Makefile.fstype
-
-ROOTOPTPKG = $(ROOT)/opt/smbcl-tests
-TESTDIR = $(ROOTOPTPKG)/tests
-INST_CMDS = $(PROG:%=$(TESTDIR)/%)
-
-# OBJS= $(LIBPROG).o
-# SRCS= $(LIBPROG).c $(FSLIBSRC)
-
-CPPFLAGS += -I../../../../uts/common
-CPPFLAGS += -I../../../../lib/libsmbfs
-
-LDLIBS += -R'$$ORIGIN/../../../usr/lib'
-LDLIBS += -lsmbfs
-LINTLIBS= -L$(ROOTLIB) -lsmbfs
-
-CFLAGS += $(CCVERBOSE)
-CERRWARN += -_gcc=-Wno-unused-variable
-CSTD= $(CSTD_GNU99)
-
-# not linted
-SMATCH=off
-
-LINTFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
-
-# CLOBBERFILES += $(LIBPROG)
-
-all: $(PROG)
-
-install: all $(ROOTOPTPKG) $(TESTDIR) $(INST_CMDS)
-
-lint:
- for f in $(SRCS); do ;\
- $(LINT.c) $$f $(LINTLIBS) ; done
-
-clobber: clean
- -$(RM) $(PROG)
-
-clean:
- -$(RM) $(OBJS)
-
-$(ROOTOPTPKG):
- $(INS.dir)
-
-$(TESTDIR):
- $(INS.dir)
-
-$(TESTDIR)/%: %
- $(INS.file)
-
-.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c b/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c
deleted file mode 100644
index 81ba8c9afc..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * Test program for the smbfs named pipe API.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libintl.h>
-
-#include <netsmb/smbfs_api.h>
-
-/*
- * This is a quick hack for testing client-side named pipes.
- * Its purpose is to test the ability to connect to a server,
- * open a pipe, send and receive data. The "hack" aspect is
- * the use of hand-crafted RPC messages, which allows testing
- * of the named pipe API separately from the RPC libraries.
- *
- * I captured the two small name pipe messages sent when
- * requesting a server info via RPC over /pipe/srvsvc and
- * dropped them into the arrays below (bind and info).
- * This program sends the two messages (with adjustments)
- * and just dumps whatever comes back over the pipe.
- * Use wireshark if you want to see decoded messages.
- */
-
-extern char *optarg;
-extern int optind, opterr, optopt;
-
-/* This is a DCE/RPC bind call for "srvsvc". */
-static const uchar_t
-srvsvc_bind[] = {
- 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01,
- 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88,
- 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
- 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
- 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 };
-
-/* This is a srvsvc "get server info" call, in two parts */
-static const uchar_t
-srvsvc_info[] = {
- 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00,
-#define INFO_RPCLEN_OFF 8
- /* V - RPC frag length */
- 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* ... and the operation number is: VVVV */
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x15, 0x00,
-#define INFO_SLEN1_OFF 28
-#define INFO_SLEN2_OFF 36
- /* server name, length 14 vv ... */
- 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00 };
- /* UNC server here, i.e.: "\\192.168.1.6" */
-
-static uchar_t sendbuf[1024];
-static uchar_t recvbuf[1024];
-static char *server;
-
-static int pipetest(struct smb_ctx *);
-
-static void
-srvinfo_usage(void)
-{
- printf("usage: srvinfo [-d domain][-u user][-p passwd] server\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c, error;
- struct smb_ctx *ctx = NULL;
- char *dom = NULL;
- char *usr = NULL;
- char *pw = NULL;
-
- while ((c = getopt(argc, argv, "vd:u:p:")) != -1) {
- switch (c) {
- case 'v':
- smb_verbose = 1;
- break;
-
- case 'd':
- dom = optarg;
- break;
- case 'u':
- usr = optarg;
- break;
- case 'p':
- pw = optarg;
- break;
- case '?':
- srvinfo_usage();
- break;
- }
- }
- if (optind >= argc)
- srvinfo_usage();
- server = argv[optind];
-
- if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
- argv[0]);
- srvinfo_usage();
- }
-
- /*
- * This section is intended to demonstrate how an
- * RPC client library might use this interface.
- */
- error = smb_ctx_alloc(&ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Set server, share, domain, user
- * (in the ctx handle).
- */
- smb_ctx_setfullserver(ctx, server);
- smb_ctx_setshare(ctx, "IPC$", USE_IPC);
- if (dom)
- smb_ctx_setdomain(ctx, dom, B_TRUE);
- if (usr)
- smb_ctx_setuser(ctx, usr, B_TRUE);
- if (pw)
- smb_ctx_setpassword(ctx, pw, NULL);
-
-
- /*
- * If this code were in smbutil or mount_smbfs, it would
- * get system and $HOME/.nsmbrc settings here, like this:
- */
-#if 0
- error = smb_ctx_readrc(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_readrc failed\n", argv[0]);
- goto out;
- }
-#endif
-
- /*
- * Resolve the server address,
- * setup derived defaults.
- */
- error = smb_ctx_resolve(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Get the session and tree.
- */
- error = smb_ctx_get_ssn(ctx);
- if (error) {
- fprintf(stderr, "//%s: login failed, error %d\n",
- server, error);
- goto out;
- }
- error = smb_ctx_get_tree(ctx);
- if (error) {
- fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
- server, "IPC$", error);
- goto out;
- }
-
- /*
- * Do some named pipe I/O.
- */
- error = pipetest(ctx);
- if (error) {
- fprintf(stderr, "pipetest, %d\n", error);
- goto out;
- }
-
-out:
- smb_ctx_free(ctx);
-
- return ((error) ? 1 : 0);
-}
-
-static void
-hexdump(const uchar_t *buf, int len) {
- int ofs = 0;
-
- while (len--) {
- if (ofs % 16 == 0)
- printf("\n%02X: ", ofs);
- printf("%02x ", *buf++);
- ofs++;
- }
- printf("\n");
-}
-
-/*
- * Put a unicode UNC server name, including the null.
- * Quick-n-dirty, just for this test...
- */
-static int
-put_uncserver(const char *s, uchar_t *buf)
-{
- uchar_t *p = buf;
- char c;
-
- *p++ = '\\'; *p++ = '\0';
- *p++ = '\\'; *p++ = '\0';
-
- do {
- c = *s++;
- if (c == '/')
- c = '\\';
- *p++ = c;
- *p++ = '\0';
-
- } while (c != 0);
-
- return (p - buf);
-}
-
-/* Get a little-endian int. Just for testing. */
-static int
-getint(const uchar_t *p)
-{
- return (p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24));
-}
-
-/*
- * Send the bind and read the ack.
- * This tests smb_fh_xactnp.
- */
-static int
-do_bind(int fid)
-{
- int err, len, more;
-
- more = 0;
- len = sizeof (recvbuf);
- err = smb_fh_xactnp(fid,
- sizeof (srvsvc_bind), (char *)srvsvc_bind,
- &len, (char *)recvbuf, &more);
- if (err) {
- printf("xact bind, err=%d\n", err);
- return (err);
- }
- if (smb_verbose) {
- printf("bind ack, len=%d\n", len);
- hexdump(recvbuf, len);
- }
- if (more > 0) {
- if (more > sizeof (recvbuf)) {
- printf("bogus more=%d\n", more);
- more = sizeof (recvbuf);
- }
- len = smb_fh_read(fid, 0,
- more, (char *)recvbuf);
- if (len == -1) {
- err = EIO;
- printf("read info resp, err=%d\n", err);
- return (err);
- }
- if (smb_verbose) {
- printf("bind ack (more), len=%d\n", len);
- hexdump(recvbuf, len);
- }
- }
-
- return (0);
-}
-
-static int
-do_info(int fid)
-{
- int err, len, rlen, wlen, x;
- uchar_t *p;
-
- /*
- * Build the info request - two parts.
- * See above: srvsvc_info
- *
- * First part: RPC header, etc.
- */
- p = sendbuf;
- len = sizeof (srvsvc_info); /* 40 */
- memcpy(p, srvsvc_info, len);
- p += len;
-
- /* Second part: UNC server name */
- len = put_uncserver(server, p);
- p += len;
- sendbuf[INFO_SLEN1_OFF] = len / 2;
- sendbuf[INFO_SLEN2_OFF] = len / 2;
-
- /* Third part: level, etc. (align4) */
- for (len = (p - sendbuf) & 3; len; len--)
- *p++ = '\0';
- *p++ = 101; /* the "level" */
- *p++ = 0; *p++ = 0; *p++ = 0;
-
- /*
- * Compute total length, and fixup RPC header.
- */
- len = p - sendbuf;
- sendbuf[INFO_RPCLEN_OFF] = len;
-
- /*
- * Send the info request, read the response.
- * This tests smb_fh_write, smb_fh_read.
- */
- wlen = smb_fh_write(fid, 0, len, (char *)sendbuf);
- if (wlen == -1) {
- err = errno;
- printf("write info req, err=%d\n", err);
- return (err);
- }
- if (wlen != len) {
- printf("write info req, short write %d\n", wlen);
- return (EIO);
- }
-
- rlen = smb_fh_read(fid, 0,
- sizeof (recvbuf), (char *)recvbuf);
- if (rlen == -1) {
- err = errno;
- printf("read info resp, err=%d\n", err);
- return (err);
- }
-
- if (smb_verbose) {
- printf("info recv, len=%d\n", rlen);
- hexdump(recvbuf, rlen);
- }
-
- x = getint(recvbuf + 4);
- if (x != 0x10) {
- printf("Data representation 0x%x not supported\n", x);
- return (ENOTSUP);
- }
- printf("Platform Id: %d\n", getint(recvbuf + 0x20));
- printf("Version Major: %d\n", getint(recvbuf + 0x28));
- printf("Version Minor: %d\n", getint(recvbuf + 0x2c));
- printf("Srv type flags: 0x%x\n", getint(recvbuf + 0x30));
-
- return (0);
-}
-
-static int
-pipetest(struct smb_ctx *ctx)
-{
- static char path[] = "/srvsvc";
- static uchar_t key[16];
- int err, fd;
-
- printf("open pipe: %s\n", path);
- fd = smb_fh_open(ctx, path, O_RDWR);
- if (fd < 0) {
- perror(path);
- return (errno);
- }
-
- /* Test this too. */
- err = smb_fh_getssnkey(fd, key, sizeof (key));
- if (err) {
- printf("getssnkey: %d\n", err);
- goto out;
- }
-
- err = do_bind(fd);
- if (err) {
- printf("do_bind: %d\n", err);
- goto out;
- }
- err = do_info(fd);
- if (err)
- printf("do_info: %d\n", err);
-
-out:
- smb_fh_close(fd);
- return (err);
-}
diff --git a/usr/src/cmd/fs.d/smbclnt/test/tconn.c b/usr/src/cmd/fs.d/smbclnt/test/tconn.c
deleted file mode 100644
index bfeac98fe0..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/test/tconn.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * Test program for opening an SMB connection directly.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <libintl.h>
-
-#include <netsmb/smb_lib.h>
-
-extern char *optarg;
-extern int optind, opterr, optopt;
-extern int smb_iod_connect(struct smb_ctx *);
-
-static char *server;
-
-static void
-tconn_usage(void)
-{
- printf("usage: tconn [-d domain][-u user][-p passwd] server\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c, error, aflags;
- struct smb_ctx *ctx = NULL;
- char *dom = NULL;
- char *usr = NULL;
- char *pw = NULL;
- char *secopt = NULL;
- struct addrinfo *ai;
-
- while ((c = getopt(argc, argv, "vd:p:s:u:")) != -1) {
- switch (c) {
- case 'v':
- smb_debug = 1;
- smb_verbose = 1;
- break;
-
- case 'd':
- dom = optarg;
- break;
- case 'u':
- usr = optarg;
- break;
- case 'p':
- pw = optarg;
- break;
- case 's':
- secopt = optarg;
- break;
- case '?':
- tconn_usage();
- break;
- }
- }
- if (optind >= argc)
- tconn_usage();
- server = argv[optind];
-
- if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
- argv[0]);
- tconn_usage();
- }
-
- /*
- * This section is intended to demonstrate how an
- * RPC client library might use this interface.
- */
- error = smb_ctx_alloc(&ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Set server, share, domain, user
- * (in the ctx handle).
- */
- smb_ctx_setfullserver(ctx, server);
- smb_ctx_setshare(ctx, "IPC$", USE_IPC);
- if (dom)
- smb_ctx_setdomain(ctx, dom, B_TRUE);
- if (usr)
- smb_ctx_setuser(ctx, usr, B_TRUE);
- if (pw)
- smb_ctx_setpassword(ctx, pw, NULL);
-
- /*
- * Hackish option to override the Authentication Type flags.
- * Sorry about exposing the flag values here, but this is
- * really a programmer's test tool. See smbfs_api.h for
- * the SMB_AT_... flag values.
- */
- if (secopt != NULL) {
- aflags = atoi(secopt);
- if (aflags < 1 || aflags > 0x1f) {
- fprintf(stderr, "%s: -s {0..31}\n", argv[0]);
- tconn_usage();
- }
- smb_ctx_setauthflags(ctx, aflags);
- }
-
- /*
- * Resolve the server address,
- * setup derived defaults.
- */
- error = smb_ctx_resolve(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
- goto out;
- }
-
- if ((ai = ctx->ct_addrinfo) == NULL) {
- fprintf(stderr, "%s: no ct_addrinfo\n", argv[0]);
- goto out;
- }
- memcpy(&ctx->ct_srvaddr, ai->ai_addr, ai->ai_addrlen);
-
- /*
- * If this code were in smbutil or mount_smbfs, it would
- * get system and $HOME/.nsmbrc settings here, like this:
- */
- error = smb_iod_connect(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_iod_connect failed\n", argv[0]);
- goto out;
- }
-
- printf("Yea, we connected!\n");
-
-out:
- smb_ctx_free(ctx);
-
- return ((error) ? 1 : 0);
-}
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common
index b1f8835acd..79b49c8ce2 100644
--- a/usr/src/cmd/mdb/Makefile.common
+++ b/usr/src/cmd/mdb/Makefile.common
@@ -22,7 +22,7 @@
#
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2016 Joyent, Inc.
-# Copyright 2016 Nexenta Systems, Inc.
+# Copyright 2017 Nexenta Systems, Inc.
#
#
@@ -35,6 +35,8 @@ COMMON_MODULES_PROC = \
libavl \
libc \
libcmdutils \
+ libfknsmb \
+ libfksmbfs \
libfksmbsrv \
libnvpair \
libproc \
diff --git a/usr/src/cmd/mdb/Makefile.module b/usr/src/cmd/mdb/Makefile.module
index 5bfdbf8434..7da9b0c586 100644
--- a/usr/src/cmd/mdb/Makefile.module
+++ b/usr/src/cmd/mdb/Makefile.module
@@ -24,6 +24,8 @@
#
# Copyright (c) 2013 by Delphix. All rights reserved.
# Copyright (c) 2018, Joyent, Inc.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
.KEEP_STATE:
@@ -177,7 +179,7 @@ lint: $$(LINTFILES)
$(MODFILE): dmod .WAIT $(MODOBJS) $$(MAPFILE-EXT)
$(LINK.c) $(ZDEFS) $(ZIGNORE) $(MAPFILE-EXT:%=-M%) $(GSHARED) \
- $(MODOBJS) -o $@ $(LDLIBS) -lc
+ $(MODOBJS) -o $@ $(LDLIBS) -lc -lproc
$(CTFMERGE) -L VERSION -o $@ $(MODOBJS)
$(POST_PROCESS_SO)
diff --git a/usr/src/cmd/mdb/common/modules/libc/libc.c b/usr/src/cmd/mdb/common/modules/libc/libc.c
index a075638ddd..b9de1dc936 100644
--- a/usr/src/cmd/mdb/common/modules/libc/libc.c
+++ b/usr/src/cmd/mdb/common/modules/libc/libc.c
@@ -23,6 +23,8 @@
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2019, Joyent, Inc.
+ * Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
#include <sys/mdb_modapi.h>
@@ -36,6 +38,7 @@
#include <string.h>
#include <thr_uberdata.h>
#include "findstack.h"
+#include <libproc.h>
static const char *
stack_flags(const stack_t *sp)
@@ -1200,6 +1203,223 @@ d_errno(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
mdb_printf("%d\n", errval);
+
+ return (DCMD_OK);
+}
+
+/*
+ * Print percent from 16-bit binary fraction [0 .. 1]
+ * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
+ *
+ * Note: This routine was copied from elfdump/common/corenote.c and modified.
+ *
+ */
+static uint_t
+pct_value(ushort_t pct)
+{
+ uint_t value = pct;
+
+ value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */
+ if (value >= 1000)
+ value = 999;
+
+ return (value);
+}
+
+static void
+psinfo_raw(psinfo_t psinfo)
+{
+ const int minspaces = 2;
+ const int spbcols = 20;
+ char sysname[SYS2STR_MAX];
+ uint_t cpu, mem;
+ char buff[32];
+ int bufflen;
+
+ mdb_printf("[ NT_PRPSINFO ]\n");
+
+ mdb_printf("\tpr_state: %d\t\t\tpr_sname: %c\n",
+ psinfo.pr_lwp.pr_state, psinfo.pr_lwp.pr_sname);
+
+ mdb_printf("\tpr_zomb: %d\t\t\tpr_nice: %d\n",
+ psinfo.pr_nzomb, psinfo.pr_lwp.pr_nice);
+
+ mdb_printf("\tpr_uid: %u\t\t\tpr_gid: %u\n",
+ psinfo.pr_uid, psinfo.pr_gid);
+
+ mdb_snprintf(buff, sizeof (buff),
+ "%d", psinfo.pr_pid);
+
+ bufflen = strlen(buff);
+ mdb_printf("\tpr_pid: %s%*spr_ppid: %d\n",
+ buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
+ psinfo.pr_ppid);
+
+ mdb_printf("\tpr_pgid: %u\t\t\tpr_sid: %d\n",
+ psinfo.pr_gid, psinfo.pr_sid);
+
+ mdb_snprintf(buff, sizeof (buff),
+ "0x%lx", (ulong_t)psinfo.pr_addr);
+
+ bufflen = strlen(buff);
+
+ mdb_printf("\tpr_addr: %s%*spr_size: %#x\n",
+ buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
+ (ulong_t)psinfo.pr_size);
+
+ mdb_printf("\tpr_rssize: %#lx\t\tpr_wchan: %#lx\n",
+ (ulong_t)psinfo.pr_rssize, (ulong_t)psinfo.pr_lwp.pr_wchan);
+
+ mdb_printf("\tpr_start:\n\t tv_sec: %ld\t\ttv_nsec: %ld\n",
+ psinfo.pr_start.tv_sec, psinfo.pr_start.tv_nsec);
+
+ mdb_printf("\tpr_time:\n\t tv_sec: %ld\t\t\ttv_nsec: %ld\n",
+ psinfo.pr_time.tv_sec, psinfo.pr_time.tv_nsec);
+
+ mdb_printf("\tpr_pri: %d\t\t\tpr_oldpri: %d\n",
+ psinfo.pr_lwp.pr_pri, psinfo.pr_lwp.pr_oldpri);
+
+ mdb_printf("\tpr_cpu: %d\n", psinfo.pr_lwp.pr_cpu);
+
+ mdb_printf("\tpr_clname: %s\n", psinfo.pr_lwp.pr_clname);
+
+ mdb_printf("\tpr_fname: %s\n", psinfo.pr_fname);
+
+ mdb_printf("\tpr_psargs: %s\n", psinfo.pr_psargs);
+
+
+ mdb_printf("\tpr_syscall: [ %s ]\n",
+ proc_sysname(psinfo.pr_lwp.pr_syscall, sysname,
+ sizeof (sysname)));
+
+ mdb_printf("\tpr_ctime:\n\t tv_sec: %ld\t\t\ttv_nsec: %ld\n",
+ psinfo.pr_ctime.tv_sec, psinfo.pr_ctime.tv_nsec);
+
+ mdb_printf("\tpr_argc: %d\t\t\tpr_argv: 0x%lx\n",
+ psinfo.pr_argc, (ulong_t)psinfo.pr_argv);
+
+ mdb_snprintf(buff, sizeof (buff), "0x%lx", (ulong_t)psinfo.pr_envp);
+
+ bufflen = strlen(buff);
+
+ mdb_printf("\tpr_envp: %s%*spr_wstat: %d\n",
+ buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
+ psinfo.pr_wstat);
+
+ cpu = pct_value(psinfo.pr_pctcpu);
+ mem = pct_value(psinfo.pr_pctmem);
+
+ mdb_printf("\tpr_pctcpu: %u.%u%%\t\tpr_pctmem: %u.%u%%\n",
+ cpu / 10, cpu % 10, mem / 10, mem % 10);
+
+ mdb_printf("\tpr_euid: %u\t\t\tpr_egid: %u\n",
+ psinfo.pr_euid, psinfo.pr_egid);
+
+ mdb_printf("\tpr_dmodel: [%s]\n",
+ proc_dmodelname(psinfo.pr_dmodel, buff, sizeof (buff)));
+}
+
+static void
+psinfo_sum(psinfo_t psinfo)
+{
+ const int minspaces = 2;
+ const int spbcols = 23;
+ char buff[64];
+ int bufflen;
+ int ms;
+
+ mdb_printf("PID: %6d (process id)\t\t"
+ "UID: %4u (real user id)\n",
+ psinfo.pr_pid, psinfo.pr_uid);
+
+ mdb_printf("PPID: %6d (parent process id)\tEUID: %4d"
+ " (effective user id)\n", psinfo.pr_ppid, psinfo.pr_euid);
+
+ mdb_printf("PGID: %6d (process group id)\tGID: %4u"
+ " (real group id)\n", psinfo.pr_pgid, psinfo.pr_gid);
+
+ mdb_printf("SID: %6d (session id)\t\tEGID: %4u"
+ " (effective group id)\n",
+ psinfo.pr_sid, psinfo.pr_egid);
+
+ mdb_printf("ZONEID: %6d\t\t\t\tCONTRACT:%4d\n",
+ psinfo.pr_zoneid, psinfo.pr_contract);
+
+ mdb_printf("PROJECT:%6d \t\t\t\tTASK: %4d\n\n",
+ psinfo.pr_projid, psinfo.pr_taskid);
+
+ mdb_printf("START: %Y (wall timestamp when the process started)\n",
+ psinfo.pr_start);
+
+ ms = NSEC2MSEC(psinfo.pr_time.tv_nsec);
+
+ mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds",
+ psinfo.pr_time.tv_sec, ms);
+
+ bufflen = strlen(buff);
+
+ mdb_printf("TIME: %s%*s"
+ "(CPU time used by this process)\n",
+ buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
+
+ ms = NSEC2MSEC(psinfo.pr_ctime.tv_nsec);
+
+ mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds",
+ psinfo.pr_ctime.tv_sec, ms);
+
+ mdb_printf("CTIME: %s%*s"
+ "(CPU time used by child processes)\n",
+ buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
+
+ mdb_snprintf(buff, sizeof (buff), "%s", psinfo.pr_fname);
+ bufflen = strlen(buff);
+
+ mdb_printf("FNAME: %s%*s(name of the program executed)\n",
+ buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
+
+ mdb_printf("PSARGS: \"%s\"\n", psinfo.pr_psargs);
+}
+
+void
+d_psinfo_dcmd_help(void)
+{
+ mdb_printf(
+ "Prints relevant fields from psinfo_t data and\n"
+ "most fields from NT_PRPSINFO note section\n\n"
+ "Usage: ::psinfo [-v]\n"
+ "Options:\n"
+ " -v verbose output\n");
+}
+
+static int
+d_psinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ psinfo_t psinfo;
+ uint_t opt_v = FALSE;
+ ssize_t nbytes;
+
+ if (mdb_getopts(argc, argv, 'v',
+ MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
+ return (DCMD_USAGE);
+
+ nbytes = mdb_get_xdata("psinfo", NULL, 0);
+
+ if (nbytes <= 0) {
+ mdb_warn("information not available for analysis");
+ return (DCMD_ERR);
+ }
+
+ if (mdb_get_xdata("psinfo", &psinfo, nbytes) != nbytes) {
+ mdb_warn("failed to read psinfo information");
+ return (DCMD_ERR);
+ }
+
+ if (opt_v) {
+ psinfo_raw(psinfo);
+ } else {
+ psinfo_sum(psinfo);
+ }
+
return (DCMD_OK);
}
@@ -1215,6 +1435,8 @@ static const mdb_dcmd_t dcmds[] = {
{ "ulwp", ":", "print ulwp_t structure", d_ulwp, NULL },
{ "uberdata", ":", "print uberdata_t structure", d_uberdata, NULL },
{ "tsd", ":-k key", "print tsd for this thread", d_tsd, NULL },
+ { "psinfo", "[-v]", "prints relevant psinfo_t data", d_psinfo,
+ d_psinfo_dcmd_help },
{ NULL }
};
diff --git a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
index 3b350a19ba..24e690f98a 100644
--- a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
+++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -35,6 +36,12 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb_pass.h>
+#ifdef _KERNEL
+#define NSMB_OBJNAME "nsmb"
+#else
+#define NSMB_OBJNAME "libfknsmb.so.1"
+#endif
+
#define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */
#define OPT_RECURSE 0x0002 /* recursive display */
@@ -66,12 +73,13 @@ print_str(uintptr_t addr)
*/
typedef struct smb_co_walk_data {
uintptr_t pp;
- int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */
+ int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE, ... */
int size; /* sizeof (union member) */
union co_u {
smb_connobj_t co; /* copy of the list element */
smb_vc_t vc;
smb_share_t ss;
+ smb_fh_t fh;
} u;
} smb_co_walk_data_t;
@@ -108,6 +116,9 @@ smb_co_walk_init(mdb_walk_state_t *wsp, int level)
case SMBL_SHARE:
smbw->size = sizeof (smbw->u.ss);
break;
+ case SMBL_FH:
+ smbw->size = sizeof (smbw->u.fh);
+ break;
default:
smbw->size = sizeof (smbw->u);
break;
@@ -146,7 +157,7 @@ smb_vc_walk_init(mdb_walk_state_t *wsp)
}
/* Locate the VC list head. */
- if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym)) {
+ if (mdb_lookup_by_obj(NSMB_OBJNAME, "smb_vclist", &sym)) {
mdb_warn("failed to lookup `smb_vclist'\n");
return (WALK_ERR);
}
@@ -174,6 +185,24 @@ smb_ss_walk_init(mdb_walk_state_t *wsp)
}
/*
+ * Walk the file hande list below some share.
+ */
+int
+smb_fh_walk_init(mdb_walk_state_t *wsp)
+{
+
+ /*
+ * Initial walk_addr is address of parent (share)
+ */
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk smb_fh does not support global walks\n");
+ return (WALK_ERR);
+ }
+
+ return (smb_co_walk_init(wsp, SMBL_FH));
+}
+
+/*
* Common walk_step for walking structs inherited
* from smb_connobj_t (smb_vc_t, smb_share_t)
*/
@@ -215,6 +244,30 @@ typedef struct smb_co_cbdata {
} smb_co_cbdata_t;
/*
+ * Call-back function for walking a file handle list.
+ */
+/* ARGSUSED */
+int
+smb_fh_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const smb_fh_t *fhp = data;
+ // smb_co_cbdata_t *cbd = arg;
+
+ mdb_inc_indent(2);
+ mdb_printf(" %-p", addr);
+ if (fhp->fh_fid2.fid_volatile != 0) {
+ mdb_printf("\t0x%llx\n",
+ (long long) fhp->fh_fid2.fid_volatile);
+ } else {
+ mdb_printf("\t0x%x\n", fhp->fh_fid1);
+ }
+
+ mdb_dec_indent(2);
+
+ return (WALK_NEXT);
+}
+
+/*
* Call-back function for walking a share list.
*/
int
@@ -222,12 +275,20 @@ smb_ss_cb(uintptr_t addr, const void *data, void *arg)
{
const smb_share_t *ssp = data;
smb_co_cbdata_t *cbd = arg;
+ uint32_t tid;
- mdb_printf(" %-p\t%s\n", addr, ssp->ss_name);
+ tid = ssp->ss2_tree_id;
+ if (tid == 0)
+ tid = ssp->ss_tid;
- if (cbd->flags & OPT_VERBOSE) {
+ mdb_printf(" %-p\t0x%x\t%s\n", addr, tid, ssp->ss_name);
+
+ if (cbd->flags & OPT_RECURSE) {
mdb_inc_indent(2);
- /* Anything wanted here? */
+ if (mdb_pwalk("nsmb_fh", smb_fh_cb, cbd, addr) < 0) {
+ mdb_warn("failed to walk 'nsmb_fh'");
+ /* Don't: return (WALK_ERR); */
+ }
mdb_dec_indent(2);
}
@@ -408,6 +469,7 @@ rqlist_walk_step(mdb_walk_state_t *wsp)
typedef struct rqlist_cbdata {
int printed_header;
+ int vcflags;
uintptr_t uid; /* optional filtering by UID */
} rqlist_cbdata_t;
@@ -423,8 +485,13 @@ rqlist_cb(uintptr_t addr, const void *data, void *arg)
}
mdb_printf(" %-p", addr); /* smb_rq_t */
- mdb_printf(" x%04x", rq->sr_mid);
- mdb_printf(" x%02x", rq->sr_cmd);
+ if ((cbd->vcflags & SMBV_SMB2) != 0) {
+ mdb_printf(" x%04llx", (long long)rq->sr2_messageid);
+ mdb_printf(" x%02x", rq->sr2_command);
+ } else {
+ mdb_printf(" x%04x", rq->sr_mid);
+ mdb_printf(" x%02x", rq->sr_cmd);
+ }
mdb_printf(" %d", rq->sr_state);
mdb_printf(" x%x", rq->sr_flags);
mdb_printf("\n");
@@ -437,9 +504,20 @@ int
rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
rqlist_cbdata_t cbd;
+ smb_vc_t *vcp;
+ size_t vcsz;
memset(&cbd, 0, sizeof (cbd));
+ /* Need the VC again to get */
+ vcsz = sizeof (*vcp);
+ vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC);
+ if (mdb_vread(vcp, vcsz, addr) != vcsz) {
+ mdb_warn("cannot read VC from %p", addr);
+ return (DCMD_ERR);
+ }
+ cbd.vcflags = vcp->vc_flags;
+
/*
* Initial walk_addr is address of parent (VC)
*/
@@ -471,7 +549,7 @@ pwtree_walk_init(mdb_walk_state_t *wsp)
return (WALK_ERR);
}
- if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym) == -1) {
+ if (mdb_lookup_by_obj(NSMB_OBJNAME, "smb_ptd", &sym) == -1) {
mdb_warn("failed to find symbol 'smb_ptd'");
return (WALK_ERR);
}
@@ -600,6 +678,8 @@ static const mdb_walker_t walkers[] = {
smb_vc_walk_init, smb_co_walk_step, NULL },
{ "nsmb_ss", "walk nsmb share list for some VC",
smb_ss_walk_init, smb_co_walk_step, NULL },
+ { "nsmb_fh", "walk nsmb share list for some VC",
+ smb_fh_walk_init, smb_co_walk_step, NULL },
{ "nsmb_rqlist", "walk request list for some VC",
rqlist_walk_init, rqlist_walk_step, NULL },
{ "nsmb_pwtree", "walk passord AVL tree",
diff --git a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
index 6be9e2a0c4..e787fd86e5 100644
--- a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
+++ b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
@@ -20,13 +20,19 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#include <sys/mdb_modapi.h>
#include <sys/types.h>
+#include <sys/mdb_modapi.h>
+
+#ifdef _USER
+#include "../genunix/avl.h"
+#define _FAKE_KERNEL
+#endif
+
#include <sys/refstr_impl.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
@@ -149,7 +155,7 @@ smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
if (!(flags & DCMD_ADDRSPEC)) {
- if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd)
+ if (mdb_walk("vfs", smbfs_vfs_cb, cbd)
== -1) {
mdb_warn("can't walk smbfs vfs");
return (DCMD_ERR);
@@ -238,7 +244,7 @@ smbfs_node_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
addr += OFFSETOF(smbmntinfo_t, smi_hash_avl);
- if (mdb_pwalk("genunix`avl", smbfs_node_cb, cbd, addr) == -1) {
+ if (mdb_pwalk("avl", smbfs_node_cb, cbd, addr) == -1) {
mdb_warn("cannot walk smbfs nodes");
return (DCMD_ERR);
}
@@ -267,10 +273,59 @@ static const mdb_dcmd_t dcmds[] = {
{NULL}
};
+#ifdef _USER
+/*
+ * Sadly, can't just compile ../genunix/vfs.c with this since
+ * it has become a catch-all for FS-specific headers etc.
+ */
+int
+vfs_walk_init(mdb_walk_state_t *wsp)
+{
+ if (wsp->walk_addr == NULL &&
+ mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
+ mdb_warn("failed to read 'rootvfs'");
+ return (WALK_ERR);
+ }
+
+ wsp->walk_data = (void *)wsp->walk_addr;
+ return (WALK_NEXT);
+}
+
+int
+vfs_walk_step(mdb_walk_state_t *wsp)
+{
+ vfs_t vfs;
+ int status;
+
+ if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) {
+ mdb_warn("failed to read vfs_t at %p", wsp->walk_addr);
+ return (WALK_DONE);
+ }
+
+ status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata);
+
+ if (vfs.vfs_next == wsp->walk_data)
+ return (WALK_DONE);
+
+ wsp->walk_addr = (uintptr_t)vfs.vfs_next;
+
+ return (status);
+}
+#endif // _USER
+
static const mdb_walker_t walkers[] = {
+#ifdef _USER
+ /* from avl.c */
+ { AVL_WALK_NAME, AVL_WALK_DESC,
+ avl_walk_init, avl_walk_step, avl_walk_fini },
+ /* from vfs.c */
+ { "vfs", "walk file system list",
+ vfs_walk_init, vfs_walk_step },
+#endif // _USER
{NULL}
};
+
static const mdb_modinfo_t modinfo = {
MDB_API_VERSION,
dcmds,
diff --git a/usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile b/usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile
new file mode 100644
index 0000000000..e6c6109a50
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfknsmb.so
+MDBTGT = proc
+
+MODSRCS = nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/nsmb
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+CPPFLAGS += -D_FAKE_KERNEL
+
+CSTD= $(CSTD_GNU99)
diff --git a/usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile b/usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile
new file mode 100644
index 0000000000..51b6d01c6d
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfksmbfs.so
+MDBTGT = proc
+
+MODSRCS = smbfs.c avl.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/smbfs
+GENUNIX_DIR = ../../../common/modules/genunix
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbsrv/libfksmbsrv/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+
+CSTD= $(CSTD_GNU99)
+
+dmod/%.o: $(GENUNIX_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+dmod/%.ln: $(GENUNIX_DIR)/%.c
+ $(LINT.c) -c $<
diff --git a/usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile b/usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile
new file mode 100644
index 0000000000..c50ac1c69d
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfknsmb.so
+MDBTGT = proc
+
+MODSRCS = nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/nsmb
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+CPPFLAGS += -D_FAKE_KERNEL
+
+CSTD= $(CSTD_GNU99)
diff --git a/usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile b/usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile
new file mode 100644
index 0000000000..892908da7a
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfksmbfs.so
+MDBTGT = proc
+
+MODSRCS = smbfs.c avl.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/smbfs
+GENUNIX_DIR = ../../../common/modules/genunix
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbsrv/libfksmbsrv/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+
+CSTD= $(CSTD_GNU99)
+
+dmod/%.o: $(GENUNIX_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+dmod/%.ln: $(GENUNIX_DIR)/%.c
+ $(LINT.c) -c $<
diff --git a/usr/src/common/smbclnt/smbfs_ntacl.c b/usr/src/common/smbclnt/smbfs_ntacl.c
index dcc0d55e79..3ff10aba82 100644
--- a/usr/src/common/smbclnt/smbfs_ntacl.c
+++ b/usr/src/common/smbclnt/smbfs_ntacl.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -33,7 +34,7 @@
#include <sys/acl.h>
#include <sys/byteorder.h>
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/cred.h>
#include <sys/cmn_err.h>
@@ -42,16 +43,18 @@
#include <sys/vnode.h>
#include <sys/vfs.h>
-#include <sys/kidmap.h>
-
-#else /* _KERNEL */
+#else /* _KERNEL || _FAKE_KERNEL */
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
-#include <idmap.h>
+#endif /* _KERNEL || _FAKE_KERNEL */
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#else /* _KERNEL */
+#include <idmap.h>
#endif /* _KERNEL */
#include <netsmb/mchain.h>
@@ -61,7 +64,7 @@
#define NT_SD_REVISION 1
#define NT_ACL_REVISION 2
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#define MALLOC(size) kmem_alloc(size, KM_SLEEP)
#define FREESZ(p, sz) kmem_free(p, sz)
#else /* _KERNEL */
@@ -887,7 +890,7 @@ ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip)
int
smbfs_acl_sd2zfs(
i_ntsd_t *sd,
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
vsecattr_t *acl_info,
#else /* _KERNEL */
acl_t *acl_info,
@@ -908,12 +911,12 @@ smbfs_acl_sd2zfs(
* sanity checks
*/
if (acl_info) {
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
if (acl_info->acl_type != ACE_T ||
acl_info->acl_aclp != NULL ||
acl_info->acl_entry_size != sizeof (ace_t))
return (EINVAL);
-#endif /* _KERNEL */
+#endif /* !_KERNEL */
if ((sd->sd_flags & SD_DACL_PRESENT) == 0)
return (EINVAL);
}
@@ -1117,7 +1120,7 @@ smbfs_acl_sd2zfs(
zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
}
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
acl_info->vsa_aclcnt = zacecnt;
acl_info->vsa_aclentp = zacep0;
acl_info->vsa_aclentsz = zacl_size;
@@ -1226,7 +1229,7 @@ smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp)
goto out;
}
p++;
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
err = ddi_strtoul(p, &np, 10, &sa);
if (err != 0)
goto out;
@@ -1409,7 +1412,7 @@ zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip)
*/
int
smbfs_acl_zfs2sd(
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
vsecattr_t *acl_info,
#else /* _KERNEL */
acl_t *acl_info,
@@ -1455,7 +1458,7 @@ smbfs_acl_zfs2sd(
return (EINVAL);
if (own_gid == (gid_t)-1)
return (EINVAL);
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
if ((acl_info->vsa_mask & VSA_ACE) == 0)
return (EINVAL);
zacecnt = acl_info->vsa_aclcnt;
diff --git a/usr/src/common/smbclnt/smbfs_ntacl.h b/usr/src/common/smbclnt/smbfs_ntacl.h
index d3ef999f58..830282cf44 100644
--- a/usr/src/common/smbclnt/smbfs_ntacl.h
+++ b/usr/src/common/smbclnt/smbfs_ntacl.h
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBFS_NTACL_H
@@ -122,7 +124,7 @@ int mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd);
* Convert an internal SD to a ZFS-style ACL.
* Get uid/gid too if pointers != NULL.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
int smbfs_acl_sd2zfs(i_ntsd_t *, vsecattr_t *, uid_t *, gid_t *);
#else /* _KERNEL */
/* See also: lib/libsmbfs/netsmb/smbfs_acl.h */
@@ -136,7 +138,7 @@ int smbfs_acl_sd2zfs(struct i_ntsd *, acl_t *, uid_t *, gid_t *);
* (when setting them) or existing, so that any
* owner@ or group@ ACEs can be translated.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
int smbfs_acl_zfs2sd(vsecattr_t *, uid_t, gid_t, uint32_t, i_ntsd_t **);
#else /* _KERNEL */
/* See also: lib/libsmbfs/netsmb/smbfs_acl.h */
diff --git a/usr/src/head/signal.h b/usr/src/head/signal.h
index 3848a93f2c..042372d679 100644
--- a/usr/src/head/signal.h
+++ b/usr/src/head/signal.h
@@ -70,7 +70,7 @@ extern const int _sys_siglistn; /* # of signal descriptions */
extern int kill(pid_t, int);
extern int sigaction(int, const struct sigaction *_RESTRICT_KYWD,
struct sigaction *_RESTRICT_KYWD);
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
extern int sigaddset(sigset_t *, int);
extern int sigdelset(sigset_t *, int);
extern int sigemptyset(sigset_t *);
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index a6877bb589..c0c5625ad5 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -271,6 +271,7 @@ SUBDIRS += \
rpcsec_gss \
sasl_plugins \
scsi \
+ smbclnt \
smbsrv \
smhba \
sun_fc \
@@ -722,6 +723,7 @@ raidcfg_plugins: libraidcfg librcm libcfgadm libpicl libpicltree
rpcsec_gss: libgss
sasl_plugins: pkcs11 libgss libsasl
scsi: libfru libumem libdevid libdevinfo
+smbclnt: libfakekernel pkcs11
smbsrv: libxnet libpthread librt libshare libidmap pkcs11 libsqlite \
libcryptoutil libreparse libcmdutils libresolv2 libsmbfs \
libuuid libfakekernel libads libgss libldap5 krb5 libmlrpc
diff --git a/usr/src/lib/libfakekernel/Makefile.com b/usr/src/lib/libfakekernel/Makefile.com
index ef1abe4072..f9135717e6 100644
--- a/usr/src/lib/libfakekernel/Makefile.com
+++ b/usr/src/lib/libfakekernel/Makefile.com
@@ -56,10 +56,15 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CSTD = $(CSTD_GNU99)
C99LMODE = -Xc99=%all
+CFLAGS += $(CCVERBOSE)
+
# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also Note: intentionally override CPPFLAGS, not +=
CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common
-CFLAGS += $(CCVERBOSE)
CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
CPPFLAGS += -D_FILE_OFFSET_BITS=64
diff --git a/usr/src/lib/libfakekernel/common/copy.c b/usr/src/lib/libfakekernel/common/copy.c
index b1eb215b5c..77bf2e8415 100644
--- a/usr/src/lib/libfakekernel/common/copy.c
+++ b/usr/src/lib/libfakekernel/common/copy.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
@@ -20,6 +20,20 @@
#include <sys/errno.h>
int
+copyin(const void *u, void *k, size_t s)
+{
+ bcopy(u, k, s);
+ return (0);
+}
+
+int
+copyout(const void *k, void *u, size_t s)
+{
+ bcopy(k, u, s);
+ return (0);
+}
+
+int
copyinstr(const char *src, char *dst, size_t max_len, size_t *copied)
{
return (copystr(src, dst, max_len, copied));
@@ -48,3 +62,17 @@ ovbcopy(const void *src, void *dst, size_t len)
{
(void) memmove(dst, src, len);
}
+
+/* ARGSUSED */
+int
+ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
+{
+ return (copyin(buf, kernbuf, size));
+}
+
+/* ARGSUSED */
+int
+ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
+{
+ return (copyout(buf, kernbuf, size));
+}
diff --git a/usr/src/lib/libfakekernel/common/cred.c b/usr/src/lib/libfakekernel/common/cred.c
index 1563f02ac9..0920599d0a 100644
--- a/usr/src/lib/libfakekernel/common/cred.c
+++ b/usr/src/lib/libfakekernel/common/cred.c
@@ -10,28 +10,51 @@
*/
/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
*/
-
#include <sys/types.h>
#include <sys/time.h>
#include <sys/thread.h>
#include <sys/cred.h>
+#include <sys/sid.h>
+#include <strings.h>
+
+/*
+ * This library does not implement real credentials. All contexts
+ * use an opaque cred_t object, and all activity happens in the
+ * context of the user who runs the program.
+ */
+
+extern struct zone zone0;
struct cred {
+ uid_t cr_uid;
+ ksid_t *cr_ksid;
uint32_t pad[100];
};
cred_t cred0;
cred_t *kcred = &cred0;
+/*
+ * Note that fksmbd uses CRED() for SMB user logons, but uses
+ * zone_kcred() for operations done internally by the server.
+ * Let CRED() (_curcred()) return &cred1, so it's different from
+ * kcred, otherwise tests like: (cred == kcred) are always true.
+ * Also, only cred1 will have a ksid (not kcred).
+ * The UID and SID are both "nobody".
+ */
+ksiddomain_t ksdom1 = {1, 5, "S-1-0", {0}};
+ksid_t ksid1 = { 60001, 0, 0, &ksdom1};
+cred_t cred1 = { 60001, &ksid1 };
+
cred_t *
_curcred(void)
{
/* Thread-specific data? */
- return (&cred0);
+ return (&cred1);
}
/*ARGSUSED*/
@@ -50,14 +73,14 @@ crhold(cred_t *cr)
uid_t
crgetuid(const cred_t *cr)
{
- return (0);
+ return (cr->cr_uid);
}
/*ARGSUSED*/
uid_t
crgetruid(const cred_t *cr)
{
- return (0);
+ return (cr->cr_uid);
}
/*ARGSUSED*/
@@ -81,8 +104,35 @@ crgetgroups(const cred_t *cr)
return (NULL);
}
+/*ARGSUSED*/
+zoneid_t
+crgetzoneid(const cred_t *cr)
+{
+ return (GLOBAL_ZONEID);
+}
+
+/*ARGSUSED*/
+struct zone *
+crgetzone(const cred_t *cr)
+{
+ return (&zone0);
+}
+
cred_t *
zone_kcred(void)
{
return (kcred);
}
+
+/*ARGSUSED*/
+ksid_t *
+crgetsid(const cred_t *cr, int i)
+{
+ return (cr->cr_ksid);
+}
+
+cred_t *
+ddi_get_cred(void)
+{
+ return (_curcred());
+}
diff --git a/usr/src/lib/libfakekernel/common/kmisc.c b/usr/src/lib/libfakekernel/common/kmisc.c
index 2849552a66..5feaa66a28 100644
--- a/usr/src/lib/libfakekernel/common/kmisc.c
+++ b/usr/src/lib/libfakekernel/common/kmisc.c
@@ -30,9 +30,12 @@
#include <fakekernel.h>
pri_t minclsyspri = 60;
+extern zone_t zone0;
/* Some kernel code takes the address of this. */
-proc_t p0;
+proc_t p0 = {
+ .p_zone = &zone0, 0
+};
proc_t *
_curproc(void)
@@ -99,11 +102,10 @@ ddi_strtoul(const char *str, char **endp, int base, unsigned long *res)
}
int
-ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *res)
+ddi_strtoull(const char *str, char **endp, int base, u_longlong_t *res)
{
- char *end;
-
- *res = strtoull(str, &end, base);
+ errno = 0;
+ *res = strtoull(str, endp, base);
if (*res == 0)
return (errno);
return (0);
@@ -116,6 +118,7 @@ delay(clock_t ticks)
(void) poll(0, 0, msec);
}
+/* ARGSUSED */
int
issig(int why)
{
diff --git a/usr/src/lib/libfakekernel/common/mapfile-vers b/usr/src/lib/libfakekernel/common/mapfile-vers
index 1c41dd9b58..aa59ad2e46 100644
--- a/usr/src/lib/libfakekernel/common/mapfile-vers
+++ b/usr/src/lib/libfakekernel/common/mapfile-vers
@@ -43,7 +43,9 @@ SYMBOL_VERSION SUNWprivate_1.1 {
aok { FLAGS = NODIRECT };
boot_time;
cmn_err;
+ copyin;
copyinstr;
+ copyout;
copystr;
cyclic_add;
@@ -56,6 +58,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
crgetgid;
crgetngroups;
crgetgroups;
+ crgetzone;
+ crgetzoneid;
crhold;
cv_broadcast;
@@ -70,12 +74,16 @@ SYMBOL_VERSION SUNWprivate_1.1 {
cv_wait;
cv_wait_sig;
+ ddi_copyin;
+ ddi_copyout;
+ ddi_get_cred;
ddi_get_lbolt64;
ddi_get_lbolt;
ddi_get_pid;
ddi_strtoul;
ddi_strtoull;
+ debug_enter;
delay;
fm_panic;
@@ -197,7 +205,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
strfree;
system_taskq;
- system_taskq_fini;
+ system_taskq_fini;
system_taskq_init;
taskq_create;
taskq_create_proc;
@@ -227,8 +235,10 @@ SYMBOL_VERSION SUNWprivate_1.1 {
vcmn_err;
vmem_qcache_reap;
vpanic;
+ vzprintf;
zone0;
zone_kcred;
+ zprintf;
zthread_create;
zthread_exit;
diff --git a/usr/src/lib/libfakekernel/common/printf.c b/usr/src/lib/libfakekernel/common/printf.c
index c8f459dd8c..bbf350b75e 100644
--- a/usr/src/lib/libfakekernel/common/printf.c
+++ b/usr/src/lib/libfakekernel/common/printf.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
* Copyright (c) 2018, Joyent, Inc.
*/
@@ -36,6 +36,7 @@
#include <fakekernel.h>
void abort(void) __NORETURN;
+void debug_enter(char *);
char *volatile panicstr;
va_list panicargs;
@@ -100,6 +101,24 @@ fakekernel_cprintf(const char *fmt, va_list adx, int flags,
fakekernel_putlog(bufp, len, flags);
}
+/* ARGSUSED */
+void
+vzprintf(zoneid_t zoneid, const char *fmt, va_list adx)
+{
+ fakekernel_cprintf(fmt, adx, SL_CONSOLE | SL_NOTE, "", "");
+}
+
+/*PRINTFLIKE2*/
+void
+zprintf(zoneid_t zoneid, const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ vzprintf(zoneid, fmt, adx);
+ va_end(adx);
+}
+
/*
* "User-level crash dump", if you will.
*/
@@ -116,6 +135,7 @@ vpanic(const char *fmt, va_list adx)
/* Call libc`assfail() so that mdb ::status works */
(void) vsnprintf(panicbuf, sizeof (panicbuf), fmt, adx);
+ debug_enter(panicbuf);
(void) assfail(panicbuf, "(panic)", 0);
abort(); /* avoid "noreturn" warnings */
@@ -164,3 +184,10 @@ cmn_err(int ce, const char *fmt, ...)
vcmn_err(ce, fmt, adx);
va_end(adx);
}
+
+/* ARGSUSED */
+void
+debug_enter(char *str)
+{
+ /* Just a place for a break point. */
+}
diff --git a/usr/src/lib/libfakekernel/common/rwlock.c b/usr/src/lib/libfakekernel/common/rwlock.c
index 17b4ca604d..edc9bfd092 100644
--- a/usr/src/lib/libfakekernel/common/rwlock.c
+++ b/usr/src/lib/libfakekernel/common/rwlock.c
@@ -23,7 +23,6 @@
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/param.h>
-#include <sys/synch32.h>
#include <sys/thread.h>
/* avoiding synch.h */
diff --git a/usr/src/lib/libfakekernel/common/sys/cmn_err.h b/usr/src/lib/libfakekernel/common/sys/cmn_err.h
index c77b22b868..b9818f58c5 100644
--- a/usr/src/lib/libfakekernel/common/sys/cmn_err.h
+++ b/usr/src/lib/libfakekernel/common/sys/cmn_err.h
@@ -64,6 +64,10 @@ extern void cmn_err(int, const char *, ...)
extern void vcmn_err(int, const char *, __va_list)
__KVPRINTFLIKE(2);
+/*PRINTFLIKE3*/
+extern void zcmn_err(zoneid_t, int, const char *, ...)
+ __KPRINTFLIKE(3);
+
/*PRINTFLIKE1*/
extern void panic(const char *, ...)
__KPRINTFLIKE(1) __NORETURN;
@@ -71,6 +75,10 @@ extern void panic(const char *, ...)
extern void vpanic(const char *, __va_list)
__KVPRINTFLIKE(1) __NORETURN;
+/*PRINTFLIKE2*/
+extern void zprintf(zoneid_t, const char *, ...)
+ __KPRINTFLIKE(2);
+
#endif /* !_ASM && (_KERNEL || _FAKE_KERNEL) */
#ifdef __cplusplus
diff --git a/usr/src/lib/libfakekernel/common/sys/cred.h b/usr/src/lib/libfakekernel/common/sys/cred.h
index d544e04275..a338214843 100644
--- a/usr/src/lib/libfakekernel/common/sys/cred.h
+++ b/usr/src/lib/libfakekernel/common/sys/cred.h
@@ -27,7 +27,7 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
@@ -66,6 +66,8 @@ extern void cred_init(void);
extern void crhold(cred_t *);
extern void crfree(cred_t *);
+extern int groupmember(gid_t, const cred_t *);
+
extern cred_t *zone_kcred(void);
extern uid_t crgetuid(const cred_t *);
@@ -75,6 +77,7 @@ extern gid_t crgetgid(const cred_t *);
extern gid_t crgetrgid(const cred_t *);
extern gid_t crgetsgid(const cred_t *);
extern zoneid_t crgetzoneid(const cred_t *);
+extern struct zone *crgetzone(const cred_t *);
extern projid_t crgetprojid(const cred_t *);
extern const gid_t *crgetgroups(const cred_t *);
diff --git a/usr/src/lib/libfakekernel/common/sys/cyclic.h b/usr/src/lib/libfakekernel/common/sys/cyclic.h
new file mode 100644
index 0000000000..56589ae7f1
--- /dev/null
+++ b/usr/src/lib/libfakekernel/common/sys/cyclic.h
@@ -0,0 +1,87 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 RackTop Systems.
+ */
+
+#ifndef _SYS_CYCLIC_H
+#define _SYS_CYCLIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ASM
+#include <sys/time.h>
+#endif /* !_ASM */
+
+#define CY_LOW_LEVEL 0
+#define CY_LOCK_LEVEL 1
+#define CY_HIGH_LEVEL 2
+#define CY_SOFT_LEVELS 2
+#define CY_LEVELS 3
+
+#ifndef _ASM
+
+typedef uintptr_t cyclic_id_t;
+typedef int cyc_index_t;
+typedef int cyc_cookie_t;
+typedef uint16_t cyc_level_t;
+typedef void (*cyc_func_t)(void *);
+typedef void *cyb_arg_t;
+
+#define CYCLIC_NONE ((cyclic_id_t)0)
+
+typedef struct cyc_handler {
+ cyc_func_t cyh_func;
+ void *cyh_arg;
+ cyc_level_t cyh_level;
+} cyc_handler_t;
+
+typedef struct cyc_time {
+ hrtime_t cyt_when;
+ hrtime_t cyt_interval;
+} cyc_time_t;
+
+#define CY_INFINITY INT64_MAX
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
+extern void cyclic_remove(cyclic_id_t);
+extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
+extern hrtime_t cyclic_getres();
+
+extern void cyclic_suspend();
+extern void cyclic_resume();
+
+#endif /* _KERNEL || _FAKE_KERNEL */
+
+#endif /* !_ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CYCLIC_H */
diff --git a/usr/src/lib/libfakekernel/common/uio.c b/usr/src/lib/libfakekernel/common/uio.c
index 3048faff58..99cb4e04e8 100644
--- a/usr/src/lib/libfakekernel/common/uio.c
+++ b/usr/src/lib/libfakekernel/common/uio.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -42,10 +42,10 @@ uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio)
}
switch (uio->uio_segflg) {
- case UIO_USERSPACE:
case UIO_USERISPACE:
return (EINVAL);
+ case UIO_USERSPACE:
case UIO_SYSSPACE:
if (rw == UIO_READ)
bcopy(p, iov->iov_base, cnt);
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index eb73039a21..dd7bd9f99b 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -27,6 +27,8 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2018, Joyent, Inc.
* Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -710,10 +712,12 @@ extern int proc_get_secflags(pid_t, prsecflags_t **);
*/
#define FLT2STR_MAX 32 /* max. string length of faults (like SIG2STR_MAX) */
#define SYS2STR_MAX 32 /* max. string length of syscalls (like SIG2STR_MAX) */
+#define DMODELSTR_MAX 32 /* max. string length of data model names */
extern char *proc_fltname(int, char *, size_t);
extern char *proc_signame(int, char *, size_t);
extern char *proc_sysname(int, char *, size_t);
+extern char *proc_dmodelname(int, char *, size_t);
/*
* Utility functions for debugging tools to convert fault, signal, and system
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index 3b2fe58812..6e5ff2c21a 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -23,6 +23,8 @@
# Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
# Copyright (c) 2013 by Delphix. All rights reserved.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -204,6 +206,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
proc_arg_xgrab;
proc_arg_xpsinfo;
proc_content2str;
+ proc_dmodelname;
proc_finistdio;
proc_fltname;
proc_fltset2str;
diff --git a/usr/src/lib/libproc/common/proc_names.c b/usr/src/lib/libproc/common/proc_names.c
index 634a79b312..314b01fbcd 100644
--- a/usr/src/lib/libproc/common/proc_names.c
+++ b/usr/src/lib/libproc/common/proc_names.c
@@ -22,6 +22,8 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
#include <stdio.h>
@@ -31,6 +33,7 @@
#include <signal.h>
#include <errno.h>
#include "libproc.h"
+#include <sys/procfs_isa.h>
static const char *
rawfltname(int flt)
@@ -482,7 +485,7 @@ proc_str2sys(const char *str, int *sysnum)
*/
char *
proc_fltset2str(const fltset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[FLT2STR_MAX], *p = buf;
size_t n;
@@ -522,7 +525,7 @@ proc_fltset2str(const fltset_t *set, const char *delim, int m,
*/
char *
proc_sigset2str(const sigset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[SIG2STR_MAX], *p = buf;
size_t n;
@@ -568,7 +571,7 @@ proc_sigset2str(const sigset_t *set, const char *delim, int m,
*/
char *
proc_sysset2str(const sysset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[SYS2STR_MAX], *p = buf;
size_t n;
@@ -703,3 +706,34 @@ proc_str2sysset(const char *s, const char *delim, int m, sysset_t *set)
}
return (NULL);
}
+
+/*
+ * Returns a string representation of a process data model.
+ * See <sys/procfs_isa.h> for possible values.
+ */
+char *
+proc_dmodelname(int dmodel, char *buf, size_t bufsz)
+{
+ static const char *const dmdls[] = {
+ "PR_MODEL_UNKNOWN",
+ "PR_MODEL_ILP32",
+ "PR_MODEL_LP64",
+ NULL
+ };
+ size_t len;
+
+ if (bufsz == 0)
+ return (NULL);
+
+ if (dmodel > PR_MODEL_LP64 || dmodel < PR_MODEL_UNKNOWN) {
+ len = snprintf(buf, bufsz, "DMODEL#%d", dmodel);
+ } else {
+ len = strlen(dmdls[dmodel]);
+ (void) strncpy(buf, dmdls[dmodel], bufsz);
+ }
+
+ if (len >= bufsz)
+ buf[bufsz-1] = '\0';
+
+ return (buf);
+}
diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.c b/usr/src/lib/libshare/smbfs/libshare_smbfs.c
index b1f19f917d..7c9b4fa58a 100644
--- a/usr/src/lib/libshare/smbfs/libshare_smbfs.c
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.c
@@ -22,6 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -70,6 +72,7 @@ static int yes_no_validator(int, char *, char *);
static int ip_address_validator(int, char *, char *);
static int minauth_validator(int, char *, char *);
static int password_validator(int, char *, char *);
+static int protocol_validator(int, char *, char *);
static int signing_validator(int, char *, char *);
int propset_changed = 0;
@@ -182,6 +185,12 @@ struct smbclnt_proto_option_defs smbclnt_proto_options[] = {
{ "signing", NULL, PROTO_OPT_SIGNING,
0, 0, MAX_VALUE_BUFLEN,
signing_validator},
+ { "min_protocol", NULL, PROTO_OPT_MIN_PROTOCOL,
+ 0, 0, MAX_VALUE_BUFLEN,
+ protocol_validator},
+ { "max_protocol", NULL, PROTO_OPT_MAX_PROTOCOL,
+ 0, 0, MAX_VALUE_BUFLEN,
+ protocol_validator},
{NULL}
};
@@ -270,18 +279,30 @@ ip_address_validator(int index, char *section, char *value)
static int
minauth_validator(int index, char *section, char *value)
{
+ int ival;
+
if (value == NULL)
return (SA_BAD_VALUE);
- if (strlen(value) == 0)
- return (SA_OK);
- if (strcmp(value, "kerberos") == 0 ||
- strcmp(value, "ntlmv2") == 0 ||
- strcmp(value, "ntlm") == 0 ||
- strcmp(value, "lm") == 0 ||
- strcmp(value, "none") == 0)
- return (SA_OK);
- else
+ ival = smb_cf_minauth_from_str(value);
+ if (ival == -1)
return (SA_BAD_VALUE);
+
+ return (SA_OK);
+}
+
+/*ARGSUSED*/
+static int
+protocol_validator(int index, char *section, char *value)
+{
+ int ival;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ ival = smb_cf_version_from_str(value);
+ if (ival == -1)
+ return (SA_BAD_VALUE);
+
+ return (SA_OK);
}
/*ARGSUSED*/
diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.h b/usr/src/lib/libshare/smbfs/libshare_smbfs.h
index 8f95e7de68..d77fef814a 100644
--- a/usr/src/lib/libshare/smbfs/libshare_smbfs.h
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.h
@@ -22,6 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,8 +61,10 @@ extern struct smbclnt_proto_option_defs smbclnt_proto_options[];
#define PROTO_OPT_DOMAIN 9
#define PROTO_OPT_WORKGROUP 10
#define PROTO_OPT_SIGNING 11
+#define PROTO_OPT_MIN_PROTOCOL 12
+#define PROTO_OPT_MAX_PROTOCOL 13
-#define SMBC_OPT_MAX PROTO_OPT_SIGNING
+#define SMBC_OPT_MAX PROTO_OPT_MAX_PROTOCOL
/*
* Flags values
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index 160494aff1..be5ad05c42 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -24,7 +24,7 @@
# Use is subject to license terms.
# Copyright 2015 Igor Kozhukhov <ikozhukhov@gmail.com>
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
# Copyright (c) 2018, Joyent, Inc.
@@ -57,21 +57,16 @@ OBJ_LIB=\
nb.o \
nb_name.o \
nb_net.o \
- nb_ssn.o \
nbns_rq.o \
- negprot.o \
newvc.o \
nls.o \
ntlm.o \
ntlmssp.o \
print.o \
- rap.o \
rcfile.o \
- rq.o \
- signing.o \
+ rc_scf.o \
spnego.o \
spnegoparse.o \
- ssnsetup.o \
ssp.o \
subr.o \
ui-sun.o \
@@ -95,7 +90,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CSTD= $(CSTD_GNU99)
-LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap
+LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap -lscf -luuid
# normal warnings...
CFLAGS += $(CCVERBOSE)
@@ -111,23 +106,21 @@ CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
-I$(SRC)/uts/common \
-I$(SRC)/common/smbclnt
+# This is pretty mature code, so let's just ignore these.
+LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2
+LINTCHECKFLAGS += -erroff=E_INCONS_VAL_TYPE_DECL2
+LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
+LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+
# Debugging
${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
-# Filter out the less important lint.
-# See lgrep.awk
-LGREP = $(AWK) -f $(SRCDIR)/lgrep.awk
-LTAIL += 2>&1 | $(LGREP)
-
all: $(LIBS)
-lint: lintcheck_t
+lint: lintcheck
include ../../Makefile.targ
-lintcheck_t: $$(SRCS)
- $(LINT.c) $(LINTCHECKFLAGS) $(SRCS) $(LDLIBS) $(LTAIL)
-
objs/%.o pics/%.o: $(CMNDIR)/%.c
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
diff --git a/usr/src/lib/libsmbfs/cflib.h b/usr/src/lib/libsmbfs/cflib.h
index 0e8d6b57ee..85db96fcfd 100644
--- a/usr/src/lib/libsmbfs/cflib.h
+++ b/usr/src/lib/libsmbfs/cflib.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _CFLIB_H_
@@ -85,6 +87,8 @@ int cf_getopt(int, char * const *, const char *);
void cf_opt_lock(void);
void cf_opt_unlock(void);
+char *cf_get_client_uuid(void);
+
int rc_getstringptr(struct rcfile *, const char *, const char *, char **);
int rc_getstring(struct rcfile *, const char *, const char *, size_t, char *);
int rc_getint(struct rcfile *, const char *, const char *, int *);
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index c1dc6886ac..ae71332e97 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -103,28 +103,21 @@ struct smb_ctx {
struct addrinfo *ct_addrinfo; /* IP addresses of the server */
struct nb_ctx *ct_nb; /* NetBIOS info. */
char *ct_locname; /* local (machine) name */
- smb_iod_ssn_t ct_iod_ssn;
- /* smbioc_oshare_t ct_sh; XXX */
int ct_minauth;
int ct_shtype_req; /* share type wanted */
char *ct_origshare;
char *ct_home;
char *ct_rpath; /* remote file name */
- /* Connection setup SMB stuff. */
- /* Strings from the SMB negotiate response. */
- char *ct_srv_OS;
- char *ct_srv_LM;
- uint32_t ct_clnt_caps;
+ /* See ssp.c */
+ void *ct_ssp_ctx;
+ smbioc_ssn_work_t ct_work;
+ smb_iod_ssn_t ct_iod_ssn;
/* NTLM auth. stuff */
uchar_t ct_clnonce[NTLM_CHAL_SZ];
uchar_t ct_srv_chal[NTLM_CHAL_SZ];
char ct_password[SMBIOC_MAX_NAME];
-
- /* See ssp.c */
- void *ct_ssp_ctx;
- smbioc_ssn_work_t ct_work;
};
@@ -133,25 +126,20 @@ struct smb_ctx {
*/
#define ct_ssn ct_iod_ssn.iod_ossn
#define ct_vopt ct_iod_ssn.iod_ossn.ssn_vopt
+#define ct_minver ct_iod_ssn.iod_ossn.ssn_minver
+#define ct_maxver ct_iod_ssn.iod_ossn.ssn_maxver
#define ct_owner ct_iod_ssn.iod_ossn.ssn_owner
#define ct_srvaddr ct_iod_ssn.iod_ossn.ssn_srvaddr
#define ct_domain ct_iod_ssn.iod_ossn.ssn_domain
-#define ct_user ct_iod_ssn.iod_ossn.ssn_user
-#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
+#define ct_user ct_iod_ssn.iod_ossn.ssn_user
+#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
#define ct_authflags ct_iod_ssn.iod_authflags
#define ct_nthash ct_iod_ssn.iod_nthash
#define ct_lmhash ct_iod_ssn.iod_lmhash
-#define ct_sopt ct_work.wk_sopt
-#define ct_iods ct_work.wk_iods
-#define ct_tran_fd ct_work.wk_iods.is_tran_fd
-#define ct_hflags ct_work.wk_iods.is_hflags
-#define ct_hflags2 ct_work.wk_iods.is_hflags2
-#define ct_vcflags ct_work.wk_iods.is_vcflags
-#define ct_ssn_key ct_work.wk_iods.is_ssn_key
-#define ct_mac_seqno ct_work.wk_iods.is_next_seq
-#define ct_mackeylen ct_work.wk_iods.is_u_maclen
-#define ct_mackey ct_work.wk_iods.is_u_mackey.lp_ptr
+#define ct_vcflags ct_work.wk_vcflags
+#define ct_ssnkey_len ct_work.wk_u_ssnkey_len
+#define ct_ssnkey_buf ct_work.wk_u_ssnkey_buf.lp_ptr
/*
@@ -169,9 +157,7 @@ struct smb_ctx {
#define SMBCF_BROWSEOK 0x00200000 /* browser dialogue may be used */
#define SMBCF_AUTHREQ 0x00400000 /* auth. dialog requested */
#define SMBCF_KCSAVE 0x00800000 /* add to keychain requested */
-#define SMBCF_XXX 0x01000000 /* mount-all, a very bad thing */
-#define SMBCF_SSNACTIVE 0x02000000 /* session setup succeeded */
-#define SMBCF_KCDOMAIN 0x04000000 /* use domain in KC lookup */
+#define SMBCF_KCDOMAIN 0x01000000 /* use domain in KC lookup */
/*
@@ -181,6 +167,8 @@ struct smb_ctx {
int smb_ctx_init(struct smb_ctx *);
void smb_ctx_done(struct smb_ctx *);
int smb_open_driver(void);
+int nsmb_ioctl(int, int, void *);
+int nsmb_close(int);
int smb_ctx_gethandle(struct smb_ctx *);
int smb_ctx_findvc(struct smb_ctx *);
@@ -208,6 +196,9 @@ int smb_iod_work(struct smb_ctx *);
int smb_open_rcfile(char *);
void smb_close_rcfile(void);
+int smb_cf_minauth_from_str(char *);
+int smb_cf_version_from_str(char *);
+
void smb_simplecrypt(char *dst, const char *src);
int smb_simpledecrypt(char *dst, const char *src);
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
index b1f4b1e198..7b87b571ff 100644
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMBFS_API_H
@@ -48,7 +49,7 @@ extern "C" {
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -122,6 +123,8 @@ int smb_ctx_setauthflags(struct smb_ctx *, int);
int smb_ctx_setcharset(struct smb_ctx *, const char *);
int smb_ctx_setfullserver(struct smb_ctx *, const char *);
int smb_ctx_setsigning(struct smb_ctx *, int ena, int req);
+int smb_ctx_setminver(struct smb_ctx *, int ver);
+int smb_ctx_setmaxver(struct smb_ctx *, int ver);
int smb_ctx_setnbflags(struct smb_ctx *, int ena, int bcast);
int smb_ctx_setscope(struct smb_ctx *, const char *);
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
index d7cc9ebbd7..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -1 +1 @@
-CIFS CLIENT SOFTWARE
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c
index 052539316b..92a3262f79 100644
--- a/usr/src/lib/libsmbfs/smb/acl_api.c
+++ b/usr/src/lib/libsmbfs/smb/acl_api.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -83,6 +85,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
return (error);
m = mbp->mb_top;
+ bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = 0;
@@ -91,7 +94,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
/*
* This does the OTW Get.
*/
- if (ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
+ if (nsmb_ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
error = errno;
goto errout;
}
@@ -120,6 +123,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
if (mbp->mb_top != m)
mb_initm(mbp, m);
+ bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = m->m_len;
@@ -128,7 +132,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
/*
* This does the OTW Set.
*/
- if (ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
+ if (nsmb_ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
error = errno;
return (error);
diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index c2ccc3361d..c231fe0e8a 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -50,336 +51,89 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <uuid/uuid.h>
#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
#include <netsmb/netbios.h>
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
+#include <cflib.h>
+
#include "charsets.h"
#include "private.h"
-
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-static int smb_connect_timeout = 30; /* seconds */
-int smb_recv_timeout = 30; /* seconds */
-
-int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
-int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
-int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
-
-/*
- * Internal set sockopt for int-sized options.
- * Borrowed from: libnsl/rpc/ti_opts.c
- */
-static int
-smb_setopt_int(int fd, int level, int name, int val)
-{
- struct t_optmgmt oreq, ores;
- struct {
- struct t_opthdr oh;
- int ival;
- } opts;
-
- /* opt header */
- opts.oh.len = sizeof (opts);
- opts.oh.level = level;
- opts.oh.name = name;
- opts.oh.status = 0;
- opts.ival = val;
-
- oreq.flags = T_NEGOTIATE;
- oreq.opt.buf = (void *)&opts;
- oreq.opt.len = sizeof (opts);
-
- ores.flags = 0;
- ores.opt.buf = NULL;
- ores.opt.maxlen = 0;
-
- if (t_optmgmt(fd, &oreq, &ores) < 0) {
- DPRINT("t_opgmgnt, t_errno = %d", t_errno);
- if (t_errno == TSYSERR)
- return (errno);
- return (EPROTO);
- }
- if (ores.flags != T_SUCCESS) {
- DPRINT("flags 0x%x, status 0x%x",
- (int)ores.flags, (int)opts.oh.status);
- return (EPROTO);
- }
-
- return (0);
-}
+#include "smb_crypt.h"
static int
-smb_setopts(int fd)
-{
- int err;
-
- /*
- * Set various socket/TCP options.
- * Failures here are not fatal -
- * just log a complaint.
- *
- * We don't need these two:
- * SO_RCVTIMEO, SO_SNDTIMEO
- */
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
- if (err) {
- DPRINT("set SO_SNDBUF, err %d", err);
- }
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
- if (err) {
- DPRINT("set SO_RCVBUF, err %d", err);
- }
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2);
- err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
- if (err) {
- DPRINT("set SO_KEEPALIVE, err %d", err);
- }
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
- err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
- if (err) {
- DPRINT("set TCP_NODELAY, err %d", err);
- }
-
- /* Set the connect timeout (in milliseconds). */
- err = smb_setopt_int(fd, IPPROTO_TCP,
- TCP_CONN_ABORT_THRESHOLD,
- smb_connect_timeout * 1000);
- if (err) {
- DPRINT("set connect timeout, err %d", err);
- }
- return (0);
-}
-
-
-int
-conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+const char *
+smb_iod_state_name(enum smbiod_state st)
{
- struct sockaddr_in6 sin6;
- char *dev = "/dev/tcp6";
- char paddrbuf[INET6_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
-
- if (sa->sa_family != AF_INET6) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin6, sizeof (sin6));
- sin6.sin6_port = htons(port);
-
- DPRINT("tcp6: %s (%d)",
- inet_ntop(AF_INET6, &sin6.sin6_addr,
- paddrbuf, sizeof (paddrbuf)), port);
+ const char *n = "(?)";
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
- return (err);
- }
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin6);
- sndcall.addr.len = sizeof (sin6);
- sndcall.addr.buf = (void *) &sin6;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
-
- DPRINT("tcp6: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * This is used for both SMB over TCP (port 445)
- * and NetBIOS - see conn_nbt().
- */
-int
-conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
-{
- struct sockaddr_in sin;
- char *dev = "/dev/tcp";
- char paddrbuf[INET_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
-
- if (sa->sa_family != AF_INET) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin, sizeof (sin));
- sin.sin_port = htons(port);
-
- DPRINT("tcp4: %s (%d)",
- inet_ntop(AF_INET, &sin.sin_addr,
- paddrbuf, sizeof (paddrbuf)), port);
-
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
- return (err);
- }
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin);
- sndcall.addr.len = sizeof (sin);
- sndcall.addr.buf = (void *) &sin;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
-
- DPRINT("tcp4: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * Open a NetBIOS connection (session, port 139)
- *
- * The optional name parameter, if passed, means
- * we found the sockaddr via NetBIOS name lookup,
- * and can just use that for our session request.
- * Otherwise (if name is NULL), we're connecting
- * by IP address, and need to come up with the
- * NetBIOS name by other means.
- */
-int
-conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
-{
- struct sockaddr_in sin;
- struct sockaddr *sa;
- char server[NB_NAMELEN];
- char workgroup[NB_NAMELEN];
- int err, nberr, port;
-
- bcopy(saarg, &sin, sizeof (sin));
- sa = (struct sockaddr *)&sin;
-
- switch (sin.sin_family) {
- case AF_NETBIOS: /* our fake AF */
- sin.sin_family = AF_INET;
+ switch (st) {
+ case SMBIOD_ST_UNINIT:
+ n = "UNINIT!";
break;
- case AF_INET:
+ case SMBIOD_ST_IDLE:
+ n = "IDLE";
+ break;
+ case SMBIOD_ST_RECONNECT:
+ n = "RECONNECT";
+ break;
+ case SMBIOD_ST_RCFAILED:
+ n = "RCFAILED";
+ break;
+ case SMBIOD_ST_CONNECTED:
+ n = "CONNECTED";
+ break;
+ case SMBIOD_ST_NEGOTIATED:
+ n = "NEGOTIATED";
+ break;
+ case SMBIOD_ST_AUTHCONT:
+ n = "AUTHCONT";
+ break;
+ case SMBIOD_ST_AUTHFAIL:
+ n = "AUTHFAIL";
+ break;
+ case SMBIOD_ST_AUTHOK:
+ n = "AUTHOK";
+ break;
+ case SMBIOD_ST_VCACTIVE:
+ n = "VCACTIVE";
+ break;
+ case SMBIOD_ST_DEAD:
+ n = "DEAD";
break;
- default:
- DPRINT("bad af %d", sin.sin_family);
- return (EINVAL);
- }
- port = IPPORT_NETBIOS_SSN;
-
- /*
- * If we have a NetBIOS name, just use it.
- * This is the path taken when we've done a
- * NetBIOS name lookup on this name to get
- * the IP address in the passed sa. Otherwise,
- * we're connecting by IP address, and need to
- * figure out what NetBIOS name to use.
- */
- if (name) {
- strlcpy(server, name, sizeof (server));
- DPRINT("given name: %s", server);
- } else {
- /*
- *
- * Try a NetBIOS node status query,
- * which searches for a type=[20] name.
- * If that doesn't work, just use the
- * (fake) "*SMBSERVER" name.
- */
- DPRINT("try node status");
- server[0] = '\0';
- nberr = nbns_getnodestatus(ctx->ct_nb,
- &sin.sin_addr, server, workgroup);
- if (nberr == 0 && server[0] != '\0') {
- /* Found the name. Save for reconnect. */
- DPRINT("found name: %s", server);
- strlcpy(ctx->ct_srvname, server,
- sizeof (ctx->ct_srvname));
- } else {
- DPRINT("getnodestatus, nberr %d", nberr);
- strlcpy(server, "*SMBSERVER", sizeof (server));
- }
- }
-
- /*
- * Establish the TCP connection.
- * Careful to close it on errors.
- */
- if ((err = conn_tcp4(ctx, sa, port)) != 0) {
- DPRINT("TCP connect: err=%d", err);
- goto out;
}
- /* Connected. Do NetBIOS session request. */
- err = nb_ssn_request(ctx, server);
- if (err)
- DPRINT("ssn_rq, err %d", err);
-
-out:
- if (err) {
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
- }
- return (err);
+ return (n);
}
/*
* Make a new connection, or reconnect.
+ *
+ * This is called first from the door service thread in smbiod
+ * (so that can report success or failure to the door client)
+ * and thereafter it's called when we need to reconnect after a
+ * network outage (or whatever might cause connection loss).
*/
int
smb_iod_connect(smb_ctx_t *ctx)
{
- struct sockaddr *sa;
- int err, err2;
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ char *uuid_str;
+ int err;
struct mbdata blob;
+ char *nego_buf = NULL;
+ uint32_t nego_len;
memset(&blob, 0, sizeof (blob));
@@ -393,15 +147,6 @@ smb_iod_connect(smb_ctx_t *ctx)
dump_ctx("smb_iod_connect", ctx);
/*
- * This may be a reconnect, so
- * cleanup if necessary.
- */
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
-
- /*
* Get local machine name.
* Full name - not a NetBIOS name.
*/
@@ -415,114 +160,235 @@ smb_iod_connect(smb_ctx_t *ctx)
}
/*
+ * Get local machine uuid.
+ */
+ uuid_str = cf_get_client_uuid();
+ if (uuid_str == NULL) {
+ err = EINVAL;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get local UUID"), err);
+ return (err);
+ }
+ (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid);
+ free(uuid_str);
+ uuid_str = NULL;
+
+ /*
* We're called with each IP address
* already copied into ct_srvaddr.
*/
ctx->ct_flags |= SMBCF_RESOLVED;
- sa = &ctx->ct_srvaddr.sa;
- switch (sa->sa_family) {
-
- case AF_INET6:
- err = conn_tcp6(ctx, sa, IPPORT_SMB);
- break;
-
- case AF_INET:
- err = conn_tcp4(ctx, sa, IPPORT_SMB);
- /*
- * If port 445 was not listening, try port 139.
- * Note: Not doing NetBIOS name lookup here.
- * We already have the IP address.
- */
- switch (err) {
- case ECONNRESET:
- case ECONNREFUSED:
- err2 = conn_nbt(ctx, sa, NULL);
- if (err2 == 0)
- err = 0;
- }
- break;
-
- case AF_NETBIOS:
- /* Like AF_INET, but use NetBIOS ssn. */
- err = conn_nbt(ctx, sa, ctx->ct_srvname);
- break;
-
- default:
- DPRINT("skipped family %d", sa->sa_family);
- err = EPROTONOSUPPORT;
- break;
- }
-
-
- if (err) {
- DPRINT("connect, err=%d", err);
+ /*
+ * Ask the drvier to connect.
+ */
+ DPRINT("Try ioctl connect...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: connect failed"),
+ err, ossn->ssn_srvname);
return (err);
}
+ DPRINT("Connect OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
/*
- * Do SMB Negotiate Protocol.
+ * Setup a buffer to recv the nego. hint.
*/
- err = smb_negprot(ctx, &blob);
+ nego_len = 4096;
+ err = mb_init_sz(&blob, nego_len);
if (err)
goto out;
+ nego_buf = blob.mb_top->m_data;
+ work->wk_u_auth_rbuf.lp_ptr = nego_buf;
+ work->wk_u_auth_rlen = nego_len;
/*
- * Empty user name means an explicit request for
- * NULL session setup, which is a special case.
- * If negotiate determined that we want to do
- * SMB signing, we have to turn that off for a
- * NULL session. [MS-SMB 3.3.5.3].
+ * Ask the driver for SMB negotiate
*/
- if (ctx->ct_user[0] == '\0') {
- /* Null user should have null domain too. */
- ctx->ct_domain[0] = '\0';
- ctx->ct_authflags = SMB_AT_ANON;
- ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
- ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
+ DPRINT("Try ioctl negotiate...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: negotiate failed"),
+ err, ossn->ssn_srvname);
+ goto out;
+ }
+ DPRINT("Negotiate OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
+
+ nego_len = work->wk_u_auth_rlen;
+ blob.mb_top->m_len = nego_len;
+
+ if (smb_debug) {
+ DPRINT("Sec. blob: %d", nego_len);
+ smb_hexdump(nego_buf, nego_len);
}
/*
* Do SMB Session Setup (authenticate)
- *
- * If the server negotiated extended security,
- * run the SPNEGO state machine, otherwise do
- * one of the old-style variants.
+ * Always "extended security" now (SPNEGO)
*/
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- err = smb_ssnsetup_spnego(ctx, &blob);
- } else {
- /*
- * Server did NOT negotiate extended security.
- * Try NTLMv2, NTLMv1, or ANON (if enabled).
- */
- if (ctx->ct_authflags & SMB_AT_NTLM2) {
- err = smb_ssnsetup_ntlm2(ctx);
- } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
- err = smb_ssnsetup_ntlm1(ctx);
- } else if (ctx->ct_authflags & SMB_AT_ANON) {
- err = smb_ssnsetup_null(ctx);
- } else {
+ DPRINT("Do session setup...");
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ if (err != 0) {
+ DPRINT("Session setup err=%d", err);
+ goto out;
+ }
+
+ /*
+ * Success! We return zero now, and our caller (normally
+ * the smbiod program) will then call smb_iod_work in a
+ * new thread to service this VC as long as necessary.
+ */
+ DPRINT("Session setup OK");
+
+out:
+ mb_done(&blob);
+
+ return (err);
+}
+
+/*
+ * smb_ssnsetup_spnego
+ *
+ * This does an SMB session setup sequence using SPNEGO.
+ * The state changes seen during this sequence are there
+ * just to help track what's going on.
+ */
+int
+smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+ struct mbdata send_mb, recv_mb;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ int err;
+
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_mb, sizeof (recv_mb));
+
+ err = ssp_ctx_create_client(ctx, hint_mb);
+ if (err)
+ goto out;
+
+ /* NULL input indicates first call. */
+ err = ssp_ctx_next_token(ctx, NULL, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
+ }
+ for (;;) {
+ err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
+ DPRINT("smb__ssnsetup rc=%d, new state=%s", err,
+ smb_iod_state_name(work->wk_out_state));
+
+ if (err == 0) {
+ /*
+ * Session setup complete w/ success.
+ * Should have state AUTHOK
+ */
+ if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
+ DPRINT("Wrong state (expected AUTHOK)");
+ }
+ break;
+ }
+
+ if (err != EINPROGRESS) {
/*
- * Don't return EAUTH, because a new
- * password prompt will not help.
+ * Session setup complete w/ failure.
+ * Should have state AUTHFAIL
*/
- DPRINT("No NTLM authflags");
- err = ENOTSUP;
+ if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) {
+ DPRINT("Wrong state (expected AUTHFAIL)");
+ }
+ goto out;
+ }
+
+ /*
+ * err == EINPROGRESS
+ * Session setup continuing.
+ * Should have state AUTHCONT
+ */
+ if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
+ DPRINT("Wrong state (expected AUTHCONT)");
+ }
+
+ /* middle calls get both in, out */
+ err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
}
}
+ /*
+ * Only get here via break in the err==0 case above,
+ * so we're finalizing a successful session setup.
+ *
+ * NULL output token here indicates the final call.
+ */
+ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
+
+ /*
+ * The session key is in ctx->ct_ssnkey_buf
+ * (a.k.a. ct_work.wk_u_ssn_key_buf)
+ */
+
out:
- mb_done(&blob);
+ /* Done with ctx->ct_ssp_ctx */
+ ssp_ctx_destroy(ctx);
- if (err) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- } else {
- /* Tell library code we have a session. */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
- DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+ return (err);
+}
+
+int smb_max_authtok_sz = 0x10000;
+
+/*
+ * Session Setup function, calling the nsmb driver.
+ *
+ * Args
+ * send_mb: [in] outgoing blob data to send
+ * recv_mb: [out] received blob data buffer
+ */
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *send_mb, struct mbdata *recv_mb)
+{
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ mbuf_t *m;
+ int err;
+
+ /* Setup receive buffer for the auth data. */
+ err = mb_init_sz(recv_mb, smb_max_authtok_sz);
+ if (err != 0)
+ return (err);
+ m = recv_mb->mb_top;
+ work->wk_u_auth_rbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_rlen = m->m_maxlen;
+
+ /* ... and the auth data to send. */
+ m = send_mb->mb_top;
+ work->wk_u_auth_wbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_wlen = m->m_len;
+
+ DPRINT("Session setup ioctl...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) {
+ err = errno;
+ if (err != 0 && err != EINPROGRESS) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: session setup "),
+ err, ossn->ssn_srvname);
+ }
}
+ DPRINT("Session setup ret %d", err);
+
+ /* Free the auth data we sent. */
+ mb_done(send_mb);
+
+ /* Setup length of received auth data */
+ m = recv_mb->mb_top;
+ m->m_len = work->wk_u_auth_rlen;
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 9455a92344..3aa67fd5f5 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -148,10 +148,6 @@ dump_ctx_flags(int flags)
printf("AUTHREQ ");
if (flags & SMBCF_KCSAVE)
printf("KCSAVE ");
- if (flags & SMBCF_XXX)
- printf("XXX ");
- if (flags & SMBCF_SSNACTIVE)
- printf("SSNACTIVE ");
if (flags & SMBCF_KCDOMAIN)
printf("KCDOMAIN ");
printf("\n");
@@ -169,6 +165,8 @@ dump_iod_ssn(smb_iod_ssn_t *is)
ssn->ssn_domain, ssn->ssn_user);
printf(" ct_vopt=0x%x, ct_owner=%d\n",
ssn->ssn_vopt, ssn->ssn_owner);
+ printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
+ ssn->ssn_minver, ssn->ssn_maxver);
printf(" ct_authflags=0x%x\n", is->iod_authflags);
printf(" ct_nthash:");
@@ -254,16 +252,16 @@ smb_ctx_init(struct smb_ctx *ctx)
ctx->ct_dev_fd = -1;
ctx->ct_door_fd = -1;
- ctx->ct_tran_fd = -1;
ctx->ct_parsedlevel = SMBL_NONE;
ctx->ct_minlevel = SMBL_NONE;
ctx->ct_maxlevel = SMBL_PATH;
/* Fill in defaults */
- ctx->ct_vopt = SMBVOPT_EXT_SEC;
+ ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
ctx->ct_owner = SMBM_ANY_OWNER;
ctx->ct_authflags = SMB_AT_DEFAULT;
ctx->ct_minauth = SMB_AT_MINAUTH;
+ ctx->ct_maxver = SMB2_DIALECT_MAX;
/*
* Default domain, user, ...
@@ -333,7 +331,12 @@ smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
cf_opt_lock();
/* Careful: no return/goto before cf_opt_unlock! */
while (error == 0) {
- opt = cf_getopt(argc, argv, STDPARAM_OPT);
+ /*
+ * Leading ':' tells this to skip unknown opts.
+ * Just get -A and -U here so we know the user
+ * for config file parsing.
+ */
+ opt = cf_getopt(argc, argv, ":AU:");
if (opt == -1)
break;
arg = cf_optarg;
@@ -398,17 +401,13 @@ smb_ctx_done(struct smb_ctx *ctx)
rpc_cleanup_smbctx(ctx);
if (ctx->ct_dev_fd != -1) {
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
}
if (ctx->ct_door_fd != -1) {
close(ctx->ct_door_fd);
ctx->ct_door_fd = -1;
}
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_srvaddr_s) {
free(ctx->ct_srvaddr_s);
ctx->ct_srvaddr_s = NULL;
@@ -441,17 +440,9 @@ smb_ctx_done(struct smb_ctx *ctx)
free(ctx->ct_rpath);
ctx->ct_rpath = NULL;
}
- if (ctx->ct_srv_OS) {
- free(ctx->ct_srv_OS);
- ctx->ct_srv_OS = NULL;
- }
- if (ctx->ct_srv_LM) {
- free(ctx->ct_srv_LM);
- ctx->ct_srv_LM = NULL;
- }
- if (ctx->ct_mackey) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
+ if (ctx->ct_ssnkey_buf) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
}
@@ -868,6 +859,37 @@ smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
return (0);
}
+/*
+ * Handle .nsmbrc "minver" option.
+ * Must be <= maxver
+ */
+int
+smb_ctx_setminver(struct smb_ctx *ctx, int ver)
+{
+ if (ver < 0 || ver > ctx->ct_maxver)
+ return (EINVAL);
+ ctx->ct_minver = (uint16_t)ver;
+ return (0);
+}
+
+/*
+ * Handle .nsmbrc "maxver" option.
+ * Must be >= minver
+ *
+ * Any "too high" value is just clamped, so the caller
+ * doesn't need to know what's the highest we support.
+ */
+int
+smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
+{
+ if (ver < 1 || ver < ctx->ct_minver)
+ return (EINVAL);
+ if (ver > SMB2_DIALECT_MAX)
+ ver = SMB2_DIALECT_MAX;
+ ctx->ct_maxver = (uint16_t)ver;
+ return (0);
+}
+
static int
smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
{
@@ -899,12 +921,11 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
}
/*
- * Suport a securty options arg, i.e. -S noext,lm,ntlm
+ * Suport a securty options arg, i.e. -S lm,ntlm
* for testing various type of authenticators.
*/
static struct nv
sectype_table[] = {
- /* noext - handled below */
{ "anon", SMB_AT_ANON },
{ "lm", SMB_AT_LM1 },
{ "ntlm", SMB_AT_NTLM1 },
@@ -930,13 +951,6 @@ smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
if (nlen == 0)
break;
- if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
- /* Don't offer extended security. */
- ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
- p += nlen;
- continue;
- }
-
/* This is rarely called, so not optimized. */
for (nv = sectype_table; nv->name; nv++) {
tlen = strlen(nv->name);
@@ -1117,6 +1131,19 @@ smb_ctx_resolve(struct smb_ctx *ctx)
assert(ctx->ct_addrinfo != NULL);
/*
+ * Empty user name means an explicit request for
+ * NULL session setup, which is a special case.
+ * (No SMB signing, per [MS-SMB] 3.3.5.3)
+ */
+ if (ctx->ct_user[0] == '\0') {
+ /* Null user should have null domain too. */
+ ctx->ct_domain[0] = '\0';
+ ctx->ct_authflags = SMB_AT_ANON;
+ ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
+ ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
+ }
+
+ /*
* If we have a user name but no password,
* check for a keychain entry.
* XXX: Only for auth NTLM?
@@ -1127,13 +1154,18 @@ smb_ctx_resolve(struct smb_ctx *ctx)
* If we don't have a p/w yet,
* try the keychain.
*/
- if (ctx->ct_password[0] == '\0')
- (void) smb_get_keychain(ctx);
+ if (ctx->ct_password[0] == '\0' &&
+ smb_get_keychain(ctx) == 0) {
+ strlcpy(ctx->ct_password, "$HASH",
+ sizeof (ctx->ct_password));
+ }
+
/*
* Mask out disallowed auth types.
*/
ctx->ct_authflags &= ctx->ct_minauth;
}
+
if (ctx->ct_authflags == 0) {
smb_error(dgettext(TEXT_DOMAIN,
"no valid auth. types"), 0);
@@ -1147,6 +1179,10 @@ smb_ctx_resolve(struct smb_ctx *ctx)
return (0);
}
+/*
+ * Note: The next three have NODIRECT binding so the
+ * "fksmbcl" development tool can provide its own.
+ */
int
smb_open_driver()
{
@@ -1164,6 +1200,19 @@ smb_open_driver()
}
int
+nsmb_close(int fd)
+{
+ return (close(fd));
+}
+
+int
+nsmb_ioctl(int fd, int cmd, void *arg)
+{
+ return (ioctl(fd, cmd, arg));
+}
+
+
+int
smb_ctx_gethandle(struct smb_ctx *ctx)
{
int fd, err;
@@ -1171,9 +1220,8 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
if (ctx->ct_dev_fd != -1) {
rpc_cleanup_smbctx(ctx);
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
- ctx->ct_flags &= ~SMBCF_SSNACTIVE;
}
fd = smb_open_driver();
@@ -1187,12 +1235,12 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
/*
* Check the driver version (paranoia)
*/
- if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
+ if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
version = 0;
if (version != NSMB_VERSION) {
smb_error(dgettext(TEXT_DOMAIN,
"incorrect driver version"), 0);
- close(fd);
+ nsmb_close(fd);
return (ENODEV);
}
@@ -1221,6 +1269,15 @@ smb_ctx_get_ssn(struct smb_ctx *ctx)
DPRINT("found an existing VC");
} else {
/*
+ * If we're authenticating (real user, not NULL session)
+ * and we don't yet have a password, return EAUTH and
+ * the caller will prompt for it and call again.
+ */
+ if (ctx->ct_user[0] != '\0' &&
+ ctx->ct_password[0] == '\0')
+ return (EAUTH);
+
+ /*
* This calls the IOD to create a new session.
*/
DPRINT("setup a new VC");
@@ -1272,7 +1329,7 @@ smb_ctx_get_tree(struct smb_ctx *ctx)
*
* The driver does the actual TCON call.
*/
- if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
+ if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
err = errno;
goto out;
}
@@ -1303,7 +1360,7 @@ smb_ctx_flags2(struct smb_ctx *ctx)
{
uint16_t flags2;
- if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
smb_error(dgettext(TEXT_DOMAIN,
"can't get flags2 for a session"), errno);
return (-1);
@@ -1321,7 +1378,7 @@ smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
if (len < SMBIOC_HASH_SZ)
return (EINVAL);
- if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
+ if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
return (errno);
return (0);
@@ -1343,6 +1400,35 @@ minauth_table[] = {
{ NULL }
};
+int
+smb_cf_minauth_from_str(char *str)
+{
+ struct nv *nvp;
+
+ for (nvp = minauth_table; nvp->name; nvp++)
+ if (strcmp(nvp->name, str) == 0)
+ return (nvp->value);
+ return (-1);
+}
+
+
+static struct nv
+smbver_table[] = {
+ { "2.1", SMB2_DIALECT_0210 },
+ { "1", 1 },
+ { NULL, 0 }
+};
+
+int
+smb_cf_version_from_str(char *str)
+{
+ struct nv *nvp;
+
+ for (nvp = smbver_table; nvp->name; nvp++)
+ if (strcmp(nvp->name, str) == 0)
+ return (nvp->value);
+ return (-1);
+}
/*
* level values:
@@ -1355,7 +1441,9 @@ static int
smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
{
char *p;
+ int ival;
int error;
+ int minver, maxver;
#ifdef KICONV_SUPPORT
if (level > 0) {
@@ -1373,19 +1461,79 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
if (level <= 1) {
/* Section is: [default] or [server] */
+ /*
+ * Handle min_protocol, max_protocol
+ * (SMB protocol versions)
+ */
+ minver = -1;
+ rc_getstringptr(smb_rc, sname, "min_protocol", &p);
+ if (p != NULL) {
+ minver = smb_cf_version_from_str(p);
+ if (minver == -1) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min_protocol value \"%s\" specified in the section %s"),
+ 0, p, sname);
+ }
+ }
+ maxver = -1;
+ rc_getstringptr(smb_rc, sname, "max_protocol", &p);
+ if (p != NULL) {
+ maxver = smb_cf_version_from_str(p);
+ if (maxver == -1) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid max_protocol value \"%s\" specified in the section %s"),
+ 0, p, sname);
+ }
+ }
+
+ /*
+ * If setting both min/max protocol,
+ * validate against each other
+ */
+ if (minver != -1 && maxver != -1) {
+ if (minver > maxver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_minver = minver;
+ ctx->ct_maxver = maxver;
+ }
+ }
+
+ /*
+ * Setting just min or max, validate against
+ * current settings
+ */
+ if (minver != -1) {
+ if (minver > ctx->ct_maxver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_minver = minver;
+ }
+ }
+ if (maxver != -1) {
+ if (maxver < ctx->ct_minver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_maxver = maxver;
+ }
+ }
+
rc_getstringptr(smb_rc, sname, "minauth", &p);
if (p) {
/*
* "minauth" was set in this section; override
* the current minimum authentication setting.
*/
- struct nv *nvp;
- for (nvp = minauth_table; nvp->name; nvp++)
- if (strcmp(p, nvp->name) == 0)
- break;
- if (nvp->name)
- ctx->ct_minauth = nvp->value;
- else {
+ ival = smb_cf_minauth_from_str(p);
+ if (ival != -1) {
+ ctx->ct_minauth = ival;
+ } else {
/*
* Unknown minimum authentication level.
*/
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index 8ca9d2cee1..3d2a431142 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -62,10 +63,16 @@
#include "private.h"
+/*
+ * It's not actually necessary to call the CLOSEFH ioctl, but doing it
+ * makes debugging a little easier. If we were to skip the ioctl,
+ * nsmb_close would cleanup the handle, here or in process exit.
+ */
int
smb_fh_close(int fd)
{
- return (close(fd));
+ (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL);
+ return (nsmb_close(fd));
}
int
@@ -96,7 +103,7 @@ smb_fh_ntcreate(
goto errout;
}
from_fd = ctx->ct_dev_fd;
- if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
err = errno;
goto errout;
}
@@ -111,7 +118,7 @@ smb_fh_ntcreate(
ioc.ioc_share_acc = share_acc;
ioc.ioc_open_disp = open_disp;
ioc.ioc_creat_opts = create_opts;
- if (ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -120,7 +127,7 @@ smb_fh_ntcreate(
errout:
if (new_fd != -1)
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
@@ -210,11 +217,10 @@ smb_fh_read(int fd, off64_t offset, size_t count,
struct smbioc_rw rwrq;
bzero(&rwrq, sizeof (rwrq));
- rwrq.ioc_fh = -1; /* tell driver to supply this */
rwrq.ioc_base = dst;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(fd, SMBIOC_READ, &rwrq) == -1) {
+ if (nsmb_ioctl(fd, SMBIOC_READ, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
@@ -227,11 +233,10 @@ smb_fh_write(int fd, off64_t offset, size_t count,
struct smbioc_rw rwrq;
bzero(&rwrq, sizeof (rwrq));
- rwrq.ioc_fh = -1; /* tell driver to supply this */
rwrq.ioc_base = (char *)src;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) {
+ if (nsmb_ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
@@ -251,21 +256,23 @@ smb_fh_xactnp(int fd,
int *rdlen, char *rdata, /* receive */
int *more)
{
- int err, rparamcnt;
- uint16_t setup[2];
-
- setup[0] = TRANS_TRANSACT_NAMED_PIPE;
- setup[1] = 0xFFFF; /* driver replaces this */
- rparamcnt = 0;
+ smbioc_xnp_t ioc;
- err = smb_t2_request(fd, 2, setup, "\\PIPE\\",
- 0, NULL, /* TX paramcnt, params */
- tdlen, (void *)tdata,
- &rparamcnt, NULL, /* no RX params */
- rdlen, rdata, more);
+ /* this gets copyin & copyout */
+ bzero(&ioc, sizeof (ioc));
+ ioc.ioc_tdlen = tdlen;
+ ioc.ioc_rdlen = *rdlen;
+ ioc.ioc_more = 0;
+ ioc.ioc_tdata = (char *)tdata;
+ ioc.ioc_rdata = rdata;
- if (err)
+ if (nsmb_ioctl(fd, SMBIOC_XACTNP, &ioc) == -1) {
*rdlen = 0;
+ return (-1);
+ }
+
+ *rdlen = ioc.ioc_rdlen;
+ *more = ioc.ioc_more;
- return (err);
+ return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
index 63c6cce242..0e781f7099 100644
--- a/usr/src/lib/libsmbfs/smb/findvc.c
+++ b/usr/src/lib/libsmbfs/smb/findvc.c
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -76,7 +78,7 @@ findvc(struct smb_ctx *ctx, struct addrinfo *ai)
bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
- if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
return (errno);
return (0);
@@ -119,7 +121,6 @@ smb_ctx_findvc(struct smb_ctx *ctx)
if (err == 0) {
/* re-use an existing VC */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
return (0);
}
}
@@ -137,7 +138,7 @@ int
smb_ctx_kill(struct smb_ctx *ctx)
{
- if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
return (errno);
return (0);
diff --git a/usr/src/lib/libsmbfs/smb/getaddr.c b/usr/src/lib/libsmbfs/smb/getaddr.c
index 67e61567a1..7c01b0d7c9 100644
--- a/usr/src/lib/libsmbfs/smb/getaddr.c
+++ b/usr/src/lib/libsmbfs/smb/getaddr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -57,6 +58,8 @@
#include "charsets.h"
#include "private.h"
+static char smb_port[16] = "445";
+
void
dump_addrinfo(struct addrinfo *ai)
{
@@ -118,7 +121,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
struct nb_ctx *nbc = ctx->ct_nb;
struct addrinfo hints, *res;
char *srvaddr_str;
- int gaierr, gaierr2;
+ int gaierr;
if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
return (EAI_NONAME);
@@ -154,19 +157,26 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res);
+ gaierr = getaddrinfo(srvaddr_str, smb_port, &hints, &res);
if (gaierr == 0) {
ctx->ct_addrinfo = res;
return (0);
}
/*
+ * If we really want to support NetBIOS, we should add
+ * an AF_NETBIOS entry to the address list here.
+ * For now, let's just skip NetBIOS.
+ * (Can we just kill NetBIOS? Please? :)
+ */
+#if 0 /* XXX Just kill NetBIOS? */
+ /*
* If regular IP name lookup failed, try NetBIOS,
* but only if given a valid NetBIOS name and if
* NetBIOS name lookup is enabled.
*/
if (nbc->nb_flags & NBCF_NS_ENABLE) {
- gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
+ int gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
if (gaierr2 == 0) {
if (res->ai_canonname)
strlcpy(ctx->ct_srvname,
@@ -176,6 +186,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
return (0);
}
}
+#endif
/*
* Return the original error from getaddrinfo
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
index 53f3c515be..38e9d5e0de 100644
--- a/usr/src/lib/libsmbfs/smb/iod_wk.c
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,22 +60,21 @@
#include "private.h"
/*
- * Be the reader thread for this VC.
+ * The user agent (smbiod) calls smb_iod_connect for the first
+ * connection to some server, and if that succeeds, will start a
+ * thread running this function, passing the smb_ctx_t
+ *
+ * This thread now enters the driver and stays there, reading
+ * network responses as long as the connection is alive.
*/
int
smb_iod_work(smb_ctx_t *ctx)
{
smbioc_ssn_work_t *work = &ctx->ct_work;
- int vcst, err = 0;
+ int err = 0;
DPRINT("server: %s", ctx->ct_srvname);
- /* Calle should have opened these */
- if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
- err = EINVAL;
- goto out;
- }
-
/*
* This is the reader / reconnect loop.
*
@@ -84,34 +84,35 @@ smb_iod_work(smb_ctx_t *ctx)
*
* XXX: Add some syslog calls in here?
*/
- vcst = SMBIOD_ST_VCACTIVE;
for (;;) {
- switch (vcst) {
+ DPRINT("state: %s",
+ smb_iod_state_name(work->wk_out_state));
+
+ switch (work->wk_out_state) {
case SMBIOD_ST_IDLE:
/*
* Wait for driver requests to arrive
* for this VC, then return here.
* Next state is normally RECONNECT.
*/
- DPRINT("state: idle");
- if (ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_IDLE, &vcst) == -1) {
+ DPRINT("Call _ioc_idle...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_IDLE, work) == -1) {
err = errno;
DPRINT("ioc_idle: err %d", err);
goto out;
}
+ DPRINT("Ret. from _ioc_idle");
continue;
case SMBIOD_ST_RECONNECT:
- DPRINT("state: reconnect");
+ DPRINT("Call _iod_connect...");
err = smb_iod_connect(ctx);
- if (err == 0) {
- vcst = SMBIOD_ST_VCACTIVE;
+ if (err == 0)
continue;
- }
- DPRINT("_iod_connect: err %d", err);
+ DPRINT("iod_connect: err %d", err);
/*
* If the error was EAUTH, retry is
* not likely to succeed either, so
@@ -119,64 +120,57 @@ smb_iod_work(smb_ctx_t *ctx)
* will need to run smbutil to get
* a new thread with new auth info.
*/
- if (err == EAUTH)
+ if (err == EAUTH) {
+ DPRINT("iod_connect: EAUTH (give up)");
goto out;
- vcst = SMBIOD_ST_RCFAILED;
- continue;
-
- case SMBIOD_ST_RCFAILED:
- DPRINT("state: rcfailed");
+ }
/*
- * Reconnect failed. Kill off any
- * requests waiting in the driver,
- * then get ready to try again.
- * Next state is normally IDLE.
+ * Reconnect failed. Notify any requests
+ * that we're not connected, and delay.
+ * Next state will be IDLE or RECONNECT.
*/
- if (ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_RCFAIL, &vcst) == -1) {
+ DPRINT("Call _iod_rcfail...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_RCFAIL, work) == -1) {
err = errno;
- DPRINT("ioc_rcfail: err %d", err);
+ DPRINT("iod_rcfail: err %d", err);
goto out;
}
continue;
- case SMBIOD_ST_VCACTIVE:
- DPRINT("state: active");
- if (ioctl(ctx->ct_dev_fd,
+ case SMBIOD_ST_AUTHOK:
+ /*
+ * This is where we enter the driver and
+ * stay there. While the connection is up
+ * the VC will have SMBIOD_ST_VCACTIVE
+ */
+ DPRINT("Call _iod_work...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_WORK, work) == -1) {
err = errno;
- DPRINT("ioc_work: err %d", err);
+ DPRINT("iod_work: err %d", err);
goto out;
}
- vcst = work->wk_out_state;
- /*
- * Go ahead and close the transport now,
- * rather than wait until reconnect to
- * this server.
- */
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
+ DPRINT("Ret. from _ioc_work");
continue;
case SMBIOD_ST_DEAD:
- DPRINT("state: dead");
+ DPRINT("got state=DEAD");
err = 0;
goto out;
default:
- DPRINT("state: BAD(%d)", vcst);
+ DPRINT("Unexpected state: %d (%s)",
+ work->wk_out_state,
+ smb_iod_state_name(work->wk_out_state));
err = EFAULT;
goto out;
}
}
out:
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_dev_fd != -1) {
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
}
diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c
index fd9bcc9496..3a89fbd550 100644
--- a/usr/src/lib/libsmbfs/smb/keychain.c
+++ b/usr/src/lib/libsmbfs/smb/keychain.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,7 +128,7 @@ smbfs_keychain_cmn(
}
err = 0;
- if (ioctl(fd, cmd, &pk) < 0) {
+ if (nsmb_ioctl(fd, cmd, &pk) < 0) {
err = errno;
goto out;
}
@@ -142,7 +142,7 @@ smbfs_keychain_cmn(
out:
if (fd != -1)
- close(fd);
+ nsmb_close(fd);
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c
index 208ec6d0a4..421a0bda37 100644
--- a/usr/src/lib/libsmbfs/smb/krb5ssp.c
+++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c
@@ -32,6 +32,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -90,7 +91,7 @@ extern MECH_OID g_stcMechOIDList [];
typedef struct krb5ssp_state {
/* Filled in by krb5ssp_init_client */
krb5_context ss_krb5ctx; /* krb5 context (ptr) */
- krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
+ krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
krb5_principal ss_krb5clp; /* client principal (ptr) */
/* Filled in by krb5ssp_get_tkt */
krb5_auth_context ss_auth; /* auth ctx. w/ server (ptr) */
@@ -107,8 +108,8 @@ krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
ulong_t len;
ulong_t bloblen = tktlen;
uchar_t krbapreq[2] = { KRB_AP_REQ, 0 };
- uchar_t *blob = NULL; /* result */
- uchar_t *b;
+ uchar_t *blob = NULL; /* result */
+ uchar_t *b;
bloblen += sizeof (krbapreq);
bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
@@ -168,7 +169,7 @@ krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server,
krb5_data outdata = {0};
krb5_error_code kerr = 0;
const char *fn = NULL;
- uchar_t *tkt;
+ uchar_t *tkt;
/* Should have these from krb5ssp_init_client. */
if (kctx == NULL || kcc == NULL) {
@@ -252,9 +253,9 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
int err;
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
- uchar_t *tkt = NULL;
+ uchar_t *tkt = NULL;
ulong_t tktlen;
- uchar_t *gtok = NULL; /* gssapi token */
+ uchar_t *gtok = NULL; /* gssapi token */
ulong_t gtoklen; /* gssapi token length */
char *prin = ctx->ct_srvname;
@@ -268,9 +269,6 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
if ((err = mb_put_mem(out_mb, gtok, gtoklen, MB_MSYSTEM)) != 0)
goto out;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN)
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
-
out:
if (gtok)
free(gtok);
@@ -383,7 +381,7 @@ krb5ssp_final(struct ssp_ctx *sp)
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
krb5_keyblock *ssn_key = NULL;
- int err, len;
+ int err;
/*
* Save the session key, used for SMB signing
@@ -398,35 +396,32 @@ krb5ssp_final(struct ssp_ctx *sp)
err = EAUTH;
goto out;
}
- memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ);
- if ((len = ssn_key->length) > SMBIOC_HASH_SZ)
- len = SMBIOC_HASH_SZ;
- memcpy(ctx->ct_ssn_key, ssn_key->contents, len);
+
+ /* Sanity check the length */
+ if (ssn_key->length > 1024) {
+ DPRINT("session key too long");
+ err = EAUTH;
+ goto out;
+ }
/*
- * Set the MAC key on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = ssn_key->length;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ssn_key->contents,
- ctx->ct_mackeylen);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
+ }
+ ctx->ct_ssnkey_buf = malloc(ssn_key->length);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
}
+ ctx->ct_ssnkey_len = ssn_key->length;
+ memcpy(ctx->ct_ssnkey_buf, ssn_key->contents, ctx->ct_ssnkey_len);
err = 0;
out:
- if (ssn_key)
+ if (ssn_key != NULL)
krb5_free_keyblock(ss->ss_krb5ctx, ssn_key);
return (err);
@@ -508,7 +503,7 @@ krb5ssp_init_client(struct ssp_ctx *sp)
krb5ssp_state_t *ss;
krb5_error_code kerr;
krb5_context kctx = NULL;
- krb5_ccache kcc = NULL;
+ krb5_ccache kcc = NULL;
krb5_principal kprin = NULL;
if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) {
diff --git a/usr/src/lib/libsmbfs/smb/lgrep.awk b/usr/src/lib/libsmbfs/smb/lgrep.awk
deleted file mode 100644
index fe6e8fa0b9..0000000000
--- a/usr/src/lib/libsmbfs/smb/lgrep.awk
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# Copyright 2012 Milan Jurik. All rights reserved.
-#
-
-# This is a "lint tail" that removes all the
-# uninteresting lines from our lint output.
-# It's nawk because sed doesn't do (a|b).
-# Also comments are easier here.
-
-# There's no lintlib for krb5 yet (CR 6911968)
-/: Warning: -lkrb5 not found/ { next; }
-/: Warning: library -lkrb5 not found/ { next; }
-
-# Kill noise from xti.h with _XOPEN_SOURCE vs not. (CR 6911717)
-/: _xti_.* .E_INCONS_ARG_DECL2./ { next; }
-/: _xti_.* .E_INCONS_ARG_USED2./ { next; }
-/: _xti_.* .E_INCONS_VAL_TYPE_DECL2./ { next; }
-
-# This is third-party code we'd rather not "fix"
-/\/spnego.c.* .E_STMT_NOT_REACHED./ { next; }
-
-# The mb_put/md_get functions are intentionally used both
-# with and without return value checks. Not a concern.
-/: mb_put_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: md_get_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# The rc_get* functions clear the out arg even on failure,
-# so most callers don't need to check the return value.
-/: rc_get[a-z]* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# These have uninteresting return values, usually ignored.
-/: (n|sm)b_ctx_readrcsection .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: nls_str_(lower|upper) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: rc_(close|freesect) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# Other functions for which we often ignore return values.
-/: [a-z]*close .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: [a-z]*flush .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: [a-z]*printf .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: mem(cpy|move|set) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: mutex_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: str[ln]?(cat|cpy) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-{ print; }
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 8f0c3905c6..a94b3bc6e1 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -19,7 +19,7 @@
#
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -36,6 +36,11 @@
# MAPFILE HEADER END
#
+#
+# Note that several things in here are NODIRECT so that the
+# "fksmbcl" development tool can provide its own versions.
+#
+
$mapfile_version 2
SYMBOL_VERSION SUNWprivate {
@@ -60,6 +65,12 @@ SYMBOL_VERSION SUNWprivate {
nls_str_toloc;
nls_str_upper;
+ nsmb_close { FLAGS = NODIRECT };
+ nsmb_ioctl { FLAGS = NODIRECT };
+
+ smb_cf_minauth_from_str;
+ smb_cf_version_from_str;
+
smb_close_rcfile;
smb_ctx_alloc;
@@ -72,6 +83,7 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_gethandle;
smb_ctx_init;
smb_ctx_kill;
+ smb_ctx_newvc { FLAGS = NODIRECT };
smb_ctx_opt;
smb_ctx_parseunc;
smb_ctx_readrc;
@@ -82,6 +94,8 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_setauthflags;
smb_ctx_setdomain;
smb_ctx_setfullserver;
+ smb_ctx_setminver;
+ smb_ctx_setmaxver;
smb_ctx_setnbflags;
smb_ctx_setpassword;
smb_ctx_setpwhash;
@@ -108,25 +122,16 @@ SYMBOL_VERSION SUNWprivate {
smb_getprogname;
smb_iod_connect;
smb_iod_door_path;
- smb_iod_open_door;
- smb_iod_start;
+ smb_iod_open_door { FLAGS = NODIRECT };
+ smb_iod_start { FLAGS = NODIRECT };
smb_iod_work;
smb_lib_init;
+ smb_open_driver { FLAGS = NODIRECT };
smb_open_printer;
smb_open_rcfile;
smb_simplecrypt;
smb_simpledecrypt;
smb_strerror;
-#
-# Functions to support the Remote Access Protocol (RAP)
- smb_rap_create;
- smb_rap_done;
- smb_rap_error;
- smb_rap_getNparam;
- smb_rap_request;
- smb_rap_setNparam;
- smb_rap_setPparam;
-#
smb_verbose { FLAGS = NODIRECT }; # data
#
# Functions to support Access Control Lists (ACLs)
diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c
deleted file mode 100644
index 319e250296..0000000000
--- a/usr/src/lib/libsmbfs/smb/nb_ssn.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * NetBIOS session service functions
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-
-#include <netsmb/netbios.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/mchain.h>
-
-#include "private.h"
-#include "charsets.h"
-
-static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
-static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
-static int nb_ssn_pollin(struct smb_ctx *, int);
-
-/*
- * Send a data message.
- */
-int
-smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
-}
-
-/*
- * Send a NetBIOS message, after
- * prepending the 4-byte header.
- */
-static int
-nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
- int mtype, int mlen)
-{
- mbuf_t *m;
- uint32_t hdr, hdrbuf;
- int err;
-
- m = mbp->mb_top;
- if (m == NULL)
- return (EINVAL);
-
- /*
- * Prepend the NetBIOS header.
- * Our mbufs leave space for this.
- */
- hdr = (mtype << 24) | mlen;
- hdrbuf = htonl(hdr);
- m->m_data -= 4;
- m->m_len += 4;
- bcopy(&hdrbuf, m->m_data, 4);
-
- /*
- * Get contiguous data (so TCP won't fragment)
- * Note: replaces mb_top.
- */
- err = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (err)
- return (err);
- m = mbp->mb_top;
-
- /*
- * Send it.
- */
- if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
- return (err);
- }
-
- return (0);
-}
-
-/*
- * Receive a data message. Discard anything else.
- * Caller must deal with EAGAIN, EINTR.
- */
-int
-smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- int err, mtype, mlen;
- err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
- if (err)
- return (err);
- if (mtype != NB_SSN_MESSAGE) {
- DPRINT("discard type 0x%x", mtype);
- mb_done(mbp);
- return (EAGAIN);
- }
- if (mlen == 0) {
- DPRINT("zero length");
- mb_done(mbp);
- return (EAGAIN);
- }
-
- return (0);
-}
-
-/*
- * Receive a NetBIOS message, any type.
- * Give caller type and length.
- */
-static int
-nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
- int *mtype, int *mlen)
-{
- char *buf;
- uint32_t hdr, hdrbuf;
- int cnt, len, err, moreflag;
- int fd = ctx->ct_tran_fd;
- int tmo = smb_recv_timeout * 1000;
-
- /*
- * Start by getting the header
- * (four bytes)
- */
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- moreflag = 0;
- cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
-
- if (cnt != sizeof (hdrbuf)) {
- DPRINT("hdr cnt %d", cnt);
- return (EPROTO);
- }
-
- /*
- * Decode the header, get the length.
- */
- hdr = ntohl(hdrbuf);
- *mtype = (hdr >> 24) & 0xff;
- *mlen = hdr & 0xffffff;
-
- if (mlen == 0)
- return (0);
-
- /*
- * Get a message buffer, read the payload
- */
- if ((err = mb_init_sz(mb, *mlen)) != 0)
- return (err);
- buf = mb->mb_top->m_data;
- len = *mlen;
- while (len > 0) {
- if (!moreflag) {
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- }
-
- moreflag = 0;
- cnt = t_rcv(fd, buf, len, &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
- buf += cnt;
- len -= cnt;
- }
- mb->mb_top->m_len = *mlen;
- mb->mb_count = *mlen;
-
- return (0);
-}
-
-int
-get_xti_err(int fd)
-{
- int look;
- if (t_errno == TSYSERR)
- return (errno);
-
- if (t_errno == TLOOK) {
- look = t_look(fd);
- switch (look) {
- case T_DISCONNECT:
- (void) t_rcvdis(fd, NULL);
- (void) t_snddis(fd, NULL);
- return (ECONNRESET);
- case T_ORDREL:
- /* Received orderly release indication */
- (void) t_rcvrel(fd);
- /* Send orderly release indicator */
- (void) t_sndrel(fd);
- return (ECONNRESET);
- }
- }
- return (EPROTO);
-}
-
-/*
- * Wait for data we can receive.
- * Timeout is mSec., as for poll(2)
- */
-static int
-nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
-{
- struct pollfd pfd[1];
- int cnt, err;
-
- pfd[0].fd = ctx->ct_tran_fd;
- pfd[0].events = POLLIN | POLLPRI;
- pfd[0].revents = 0;
- cnt = poll(pfd, 1, tmo);
- switch (cnt) {
- case 0:
- err = ETIME;
- break;
- case -1:
- err = errno;
- break;
- default:
- err = 0;
- break;
- }
- return (err);
-}
-
-/*
- * Send a NetBIOS session request and
- * wait for the response.
- */
-int
-nb_ssn_request(struct smb_ctx *ctx, char *srvname)
-{
- struct mbdata req, res;
- struct nb_name lcl, srv;
- int err, mtype, mlen;
- char *ucwks;
-
- bzero(&req, sizeof (req));
- bzero(&res, sizeof (res));
-
- if ((err = mb_init(&req)) != 0)
- goto errout;
-
- ucwks = utf8_str_toupper(ctx->ct_locname);
- if (ucwks == NULL) {
- err = ENOMEM;
- goto errout;
- }
-
- /* Local NB name. */
- snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
- lcl.nn_type = NBT_WKSTA;
- lcl.nn_scope = ctx->ct_nb->nb_scope;
-
- /* Server NB name */
- snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
- srv.nn_type = NBT_SERVER;
- srv.nn_scope = ctx->ct_nb->nb_scope;
-
- /*
- * Build the request. Header is prepended later.
- */
- if ((err = nb_name_encode(&req, &srv)) != 0)
- goto errout;
- if ((err = nb_name_encode(&req, &lcl)) != 0)
- goto errout;
-
- /*
- * Send it, wait for the reply.
- */
- err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
- if (err) {
- DPRINT("send, err %d", err);
- goto errout;
- }
- err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
- if (err) {
- DPRINT("recv, err %d", err);
- goto errout;
- }
-
- if (mtype != NB_SSN_POSRESP) {
- DPRINT("recv, mtype 0x%x", mtype);
- err = ECONNREFUSED;
- goto errout;
- }
-
- return (0);
-
-errout:
- mb_done(&res);
- mb_done(&req);
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
deleted file mode 100644
index 770b742c44..0000000000
--- a/usr/src/lib/libsmbfs/smb/negprot.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Negotiate Protocol, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/netbios.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/smb_dev.h>
-
-#include "charsets.h"
-#include "smb_crypt.h"
-#include "private.h"
-
-/*
- * SMB dialects that we know about.
- */
-struct smb_dialect {
- int d_id;
- const char *d_name;
-};
-static struct smb_dialect smb_dialects[] = {
- {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
- {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
- {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
- {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
- {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
- {-1, NULL}
-};
-
-#define SMB_DIALECT_MAX \
- (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
-
-static const uint32_t smb_clnt_caps_mask =
- SMB_CAP_UNICODE |
- SMB_CAP_LARGE_FILES |
- SMB_CAP_NT_SMBS |
- SMB_CAP_STATUS32 |
- SMB_CAP_EXT_SECURITY;
-
-/*
- * SMB Negotiate Protocol
- * Based on code from the driver: smb_smb.c
- *
- * If using Extended Security, oblob (output)
- * will hold the initial security "hint".
- */
-int
-smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
-{
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp;
- struct mbdata *mbp;
- struct smb_dialect *dp;
- int err, len;
- uint8_t wc, eklen;
- uint16_t dindex, bc;
- int will_sign = 0;
-
- /*
- * Initialize: vc_hflags and vc_hflags2.
- * Note: ctx->ct_hflags* are copied into the
- * (per request) rqp->rq_hflags* by smb_rq_init.
- *
- * Like Windows, set FLAGS2_UNICODE in our first request,
- * even though technically we don't yet know whether the
- * server supports Unicode. Will clear this flag below
- * if we find out it doesn't. Need to do this because
- * some servers reject all non-Unicode requests.
- */
- ctx->ct_hflags =
- SMB_FLAGS_CASELESS |
- SMB_FLAGS_CANONICAL_PATHNAMES;
- ctx->ct_hflags2 =
- SMB_FLAGS2_KNOWS_LONG_NAMES |
- SMB_FLAGS2_KNOWS_EAS |
- /* SMB_FLAGS2_IS_LONG_NAME |? */
- /* EXT_SEC (see below) */
- SMB_FLAGS2_ERR_STATUS |
- SMB_FLAGS2_UNICODE;
-
- /*
- * Sould we offer extended security?
- * We'll turn this back off below if
- * the server doesn't support it.
- */
- if (ctx->ct_vopt & SMBVOPT_EXT_SEC)
- ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC;
-
- /*
- * The initial UID needs to be zero,
- * or Windows XP says "bad user".
- * The initial TID is all ones, but
- * we don't use it or store it here
- * because the driver handles that.
- */
- is->is_smbuid = 0;
-
- /*
- * In case we're reconnecting,
- * free previous stuff.
- */
- ctx->ct_mac_seqno = 0;
- if (ctx->ct_mackey != NULL) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
- ctx->ct_mackeylen = 0;
- }
-
- sv = &ctx->ct_sopt;
- bzero(sv, sizeof (struct smb_sopt));
-
- err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp);
- if (err)
- return (err);
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- mb_put_uint8(mbp, 0); /* word count */
- smb_rq_bstart(rqp);
- for (dp = smb_dialects; dp->d_id != -1; dp++) {
- mb_put_uint8(mbp, SMB_DT_DIALECT);
- mb_put_astring(mbp, dp->d_name);
- }
- smb_rq_bend(rqp);
-
- /*
- * This does the OTW call
- */
- err = smb_rq_internal(ctx, rqp);
- if (err) {
- DPRINT("call failed, err %d", err);
- goto errout;
- }
- if (rqp->rq_status != 0) {
- DPRINT("nt status 0x%x", rqp->rq_status);
- err = EBADRPC;
- goto errout;
- }
-
- /*
- * Decode the response
- *
- * Comments to right show names as described in
- * The Microsoft SMB Protocol spec. [MS-SMB]
- * section 2.2.3
- */
- mbp = &rqp->rq_rp;
- (void) md_get_uint8(mbp, &wc);
- err = md_get_uint16le(mbp, &dindex);
- if (err || dindex > SMB_DIALECT_MAX) {
- DPRINT("err %d dindex %d", err, (int)dindex);
- goto errout;
- }
- dp = smb_dialects + dindex;
- sv->sv_proto = dp->d_id;
- DPRINT("Dialect %s", dp->d_name);
- if (dp->d_id < SMB_DIALECT_NTLM0_12) {
- /* XXX: User-visible warning too? */
- DPRINT("old dialect %s", dp->d_name);
- goto errout;
- }
- if (wc != 17) {
- DPRINT("bad wc %d", (int)wc);
- goto errout;
- }
- md_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */
- md_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */
- md_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */
- md_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */
- md_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */
- md_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */
- md_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */
- md_get_mem(mbp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
- md_get_uint16le(mbp, (uint16_t *)&sv->sv_tz);
- md_get_uint8(mbp, &eklen); /* EncryptionKeyLength */
- err = md_get_uint16le(mbp, &bc); /* ByteCount */
- if (err)
- goto errout;
-
- /* BEGIN CSTYLED */
- /*
- * Will we do SMB signing? Or block the connection?
- * The table below describes this logic. References:
- * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
- * http://msdn.microsoft.com/en-us/library/cc212511.aspx
- * http://msdn.microsoft.com/en-us/library/cc212929.aspx
- *
- * Srv/Cli | Required | Enabled | If Required | Disabled
- * ------------+----------+------------+-------------+-----------
- * Required | Signed | Signed | Signed | Blocked [1]
- * ------------+----------+------------+-------------+-----------
- * Enabled | Signed | Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * If Required | Signed | Not Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * Disabled | Blocked | Not Signed | Not Signed | Not Signed
- *
- * [1] Like Windows 2003 and later, we don't really implement
- * the "Disabled" setting. Instead we implement "If Required",
- * so we always sign if the server requires signing.
- */
- /* END CSTYLED */
-
- if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
- /*
- * Server requires signing. We will sign,
- * even if local setting is "disabled".
- */
- will_sign = 1;
- } else if (sv->sv_sm & SMB_SM_SIGS) {
- /*
- * Server enables signing (client's option).
- * If enabled locally, do signing.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED)
- will_sign = 1;
- /* else not signing. */
- } else {
- /*
- * Server does not support signing.
- * If we "require" it, bail now.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) {
- DPRINT("Client requires signing "
- "but server has it disabled.");
- err = EBADRPC;
- goto errout;
- }
- }
-
- if (will_sign) {
- ctx->ct_vcflags |= SMBV_WILL_SIGN;
- }
- DPRINT("Security signatures: %d", will_sign);
-
- /* See comment above re. FLAGS2_UNICODE */
- if (sv->sv_caps & SMB_CAP_UNICODE)
- ctx->ct_vcflags |= SMBV_UNICODE;
- else
- ctx->ct_hflags2 &= ~SMB_FLAGS2_UNICODE;
-
- if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
- /*
- * They don't do NT error codes.
- *
- * If we send requests with
- * SMB_FLAGS2_ERR_STATUS set in
- * Flags2, Windows 98, at least,
- * appears to send replies with that
- * bit set even though it sends back
- * DOS error codes. (They probably
- * just use the request header as
- * a template for the reply header,
- * and don't bother clearing that bit.)
- *
- * Therefore, we clear that bit in
- * our vc_hflags2 field.
- */
- ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
- }
- if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
- sv->sv_maxtx < 4096 &&
- (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
- ctx->ct_vcflags |= SMBV_WIN95;
- DPRINT("Win95 detected");
- }
-
- /*
- * The rest of the message varies depending on
- * whether we've negotiated "extended security".
- *
- * With extended security, we have:
- * Server_GUID (length 16)
- * Security_BLOB
- * Otherwise we have:
- * EncryptionKey (length is eklen)
- * PrimaryDomain
- */
- if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
- struct mbuf *m;
- DPRINT("Ext.Security: yes");
-
- /*
- * Skip the server GUID.
- */
- err = md_get_mem(mbp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
- if (err)
- goto errout;
- /*
- * Remainder is the security blob.
- * Note: eklen "must be ignored" [MS-SMB]
- */
- len = (int)bc - SMB_GUIDLEN;
- if (len < 0)
- goto errout;
-
- /*
- * Get the (optional) SPNEGO "hint".
- */
- err = md_get_mbuf(mbp, len, &m);
- if (err)
- goto errout;
- mb_initm(oblob, m);
- oblob->mb_count = len;
- } else {
- DPRINT("Ext.Security: no");
- ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC;
-
- /*
- * Save the "Encryption Key" (the challenge).
- *
- * Sanity check: make sure the sec. blob length
- * isn't bigger than the byte count.
- */
- if (bc < eklen || eklen < NTLM_CHAL_SZ) {
- err = EBADRPC;
- goto errout;
- }
- err = md_get_mem(mbp, ctx->ct_srv_chal,
- NTLM_CHAL_SZ, MB_MSYSTEM);
- /*
- * Server domain follows (ignored)
- * Note: NOT aligned(2) - unusual!
- */
- }
-
- smb_rq_done(rqp);
-
- /*
- * A few sanity checks on what we received,
- * becuse we will send these in ssnsetup.
- *
- * Maximum outstanding requests (we care),
- * and Max. VCs (we only use one). Also,
- * MaxBufferSize lower limit per spec.
- */
- if (sv->sv_maxmux < 1)
- sv->sv_maxmux = 1;
- if (sv->sv_maxvcs < 1)
- sv->sv_maxvcs = 1;
- if (sv->sv_maxtx < 1024)
- sv->sv_maxtx = 1024;
-
- /*
- * Maximum transfer size.
- * Sanity checks:
- *
- * Let's be conservative about an upper limit here.
- * Win2k uses 16644 (and others) so 32k should be a
- * reasonable sanity limit for this value.
- *
- * Note that this limit does NOT affect READX/WRITEX
- * with CAP_LARGE_..., which we nearly always use.
- */
- is->is_txmax = sv->sv_maxtx;
- if (is->is_txmax > 0x8000)
- is->is_txmax = 0x8000;
-
- /*
- * Max read/write sizes, WITHOUT overhead.
- * This is just the payload size, so we must
- * leave room for the SMB headers, etc.
- * This is just the ct_txmax value, but
- * reduced and rounded down. Tricky bit:
- *
- * Servers typically give us a value that's
- * some nice "round" number, i.e 0x4000 plus
- * some overhead, i.e. Win2k: 16644==0x4104
- * Subtract for the SMB header (32) and the
- * SMB command word and byte vectors (34?),
- * then round down to a 512 byte multiple.
- */
- len = is->is_txmax - 68;
- len &= 0xFE00;
- /* XXX: Not sure yet which of these to keep. */
- is->is_rwmax = len;
- is->is_rxmax = len;
- is->is_wxmax = len;
-
- /*
- * Most of the "capability" bits we offer in session setup
- * are just copied from those offered by the server.
- */
- ctx->ct_clnt_caps = sv->sv_caps & smb_clnt_caps_mask;
-
- /* Get the client nonce. */
- (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
-
- return (0);
-
-errout:
- smb_rq_done(rqp);
- if (err == 0)
- err = EBADRPC;
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
index 9f08a2eaca..44b26f54e6 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.c
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -184,7 +184,8 @@ ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
*/
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -229,7 +230,7 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -245,7 +246,8 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
*/
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
MD5_CTX context;
uchar_t challenges[2 * NTLM_CHAL_SZ];
@@ -299,7 +301,7 @@ ntlm_put_v1x_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -477,7 +479,8 @@ ntlm_v2_session_key(uchar_t *ssn_key,
*/
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -547,7 +550,7 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
/*
* Compute the session key
*/
- ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
+ ntlm_v2_session_key(ssn_key, v2hash, ntresp);
out:
if (err) {
@@ -650,37 +653,13 @@ out:
}
/*
- * Build the MAC key (for SMB signing)
- */
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp)
-{
- struct mbuf *m;
- size_t len;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- m = ntresp_mbp->mb_top;
- len = NTLM_HASH_SZ + m->m_len;
- if ((p = malloc(len)) == NULL)
- return (ENOMEM);
- ctx->ct_mackeylen = len;
- ctx->ct_mackey = p;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
- return (0);
-}
-
-/*
* Helper for ntlmssp_put_type3 - Build the "key exchange key"
* used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
* HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
*/
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey)
{
uchar_t data[NTLM_HASH_SZ];
uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
@@ -690,6 +669,6 @@ ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
/* HMAC_MD5(SessionBaseKey, concat(...)) */
- HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ,
+ HMACT64(kxkey, ssn_key, NTLM_HASH_SZ,
data, NTLM_HASH_SZ);
}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h
index 447033b516..d0c093689a 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.h
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLM_H
@@ -38,7 +39,7 @@
* NTLM_HASH_SZ: 16 bytes (see smb_lib.h)
* NTLM_CHAL_SZ: 8 bytes (see smb_lib.h)
*/
-#define NTLM_V1_RESP_SZ 24 /* response size */
+#define NTLM_V1_RESP_SZ 24 /* response size */
#define NAMETYPE_EOL 0x0000 /* end of list of names */
#define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */
@@ -57,20 +58,21 @@ ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *);
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
-
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey);
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey);
#endif /* _NTLM_H */
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
index f39fa594ec..5ae583114d 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -67,13 +67,14 @@
#include "ntlmssp.h"
/* A shorter alias for a crazy long name from [MS-NLMP] */
-#define NTLMSSP_NEGOTIATE_NTLM2 \
+#define NTLMSSP_NEGOTIATE_ESS \
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
typedef struct ntlmssp_state {
uint32_t ss_flags;
char *ss_target_name; /* Primary domain or server name */
struct mbuf *ss_target_info;
+ uchar_t ss_ssnkey[NTLM_HASH_SZ];
uchar_t ss_kxkey[NTLM_HASH_SZ];
} ntlmssp_state_t;
@@ -90,8 +91,7 @@ struct sec_buf {
static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
static int
-ntlm_rand_ssn_key(struct smb_ctx *ctx,
- ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
+ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
/*
* Get a "security buffer" (header part)
@@ -249,16 +249,14 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
NTLMSSP_NEGOTIATE_SEAL |
/* NTLMSSP_NEGOTIATE_LM_KEY (never) */
NTLMSSP_NEGOTIATE_NTLM |
- /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
- NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_ESS |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_56;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
+ if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
@@ -447,15 +445,20 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
/*
* We're setting up a NULL session, meaning
* the lm_mbc, nt_mbc parts remain empty.
- * Let's add the "anon" flag (hint).
- * As there is no session key, disable the
- * fancy session key stuff.
+ * Let's add the "anon" flag (hint), and
+ * as we have no OWF hashes, we can't use
+ * "extended session security" (_ESS).
+ * The SessionBaseKey is all zeros, so
+ * the KeyExchangeKey is too. Otherwise
+ * this is like NTLMv2/LMv2
*/
- hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
- ssp_st->ss_flags &= ~(
- NTLMSSP_NEGOTIATE_NTLM2 |
- NTLMSSP_NEGOTIATE_KEY_EXCH);
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
+ hdr.h_flags = ssp_st->ss_flags;
err = 0;
+ /* KeyExchangeKey = SessionBaseKey = (zeros) */
+ memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
+ memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
} else if (ctx->ct_authflags & SMB_AT_NTLM2) {
/*
* Doing NTLMv2/LMv2
@@ -465,47 +468,49 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
if (err)
goto out;
err = ntlm_put_v2_responses(ctx, &ti_mbc,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
-
- } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* KeyExchangeKey = SessionBaseKey (v2) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
+ } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {
/*
* Doing NTLM ("v1x") which is NTLM with
* "Extended Session Security"
*/
err = ntlm_put_v1x_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* Compute the "Key exchange key". */
- ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
+ /*
+ * "v1x computes the KeyExchangeKey from both the
+ * server and client nonce and (v1) SessionBaseKey.
+ */
+ ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
+ ssp_st->ss_kxkey);
} else {
/*
* Doing plain old NTLM (and LM if enabled)
*/
err = ntlm_put_v1_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ /* KeyExchangeKey = SessionBaseKey (v1) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
}
/*
- * Compute the "Exported Session Key" and (possibly)
- * the "Encrypted Random Sesion Key".
- * [MS-NLMP 3.1.5.1.2]
+ * Compute the "ExportedSessionKey" and (possibly) the
+ * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]
*/
if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
+ err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
if (err)
goto out;
} else {
/* ExportedSessionKey is the KeyExchangeKey */
- memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
+ memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
/* EncryptedRandomSessionKey remains NULL */
}
@@ -590,7 +595,6 @@ out:
*/
static int
ntlm_rand_ssn_key(
- struct smb_ctx *ctx,
ntlmssp_state_t *ssp_st,
struct mbdata *ek_mbp)
{
@@ -603,12 +607,12 @@ ntlm_rand_ssn_key(
encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
/* Set "ExportedSessionKey to NONCE(16) */
- (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
+ (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
/* Set "EncryptedRandomSessionKey" to RC4(...) */
err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
ssp_st->ss_kxkey, NTLM_HASH_SZ,
- ctx->ct_ssn_key, NTLM_HASH_SZ);
+ ssp_st->ss_ssnkey, NTLM_HASH_SZ);
return (err);
}
@@ -617,34 +621,29 @@ ntlm_rand_ssn_key(
* ntlmssp_final
*
* Called after successful authentication.
- * Setup the MAC key for signing.
+ * Save the session key.
*/
int
ntlmssp_final(struct ssp_ctx *sp)
{
struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
int err = 0;
/*
- * MAC_key is just the session key, but
- * Only on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = NTLM_HASH_SZ;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
+ ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ ctx->ct_ssnkey_len = NTLM_HASH_SZ;
+ memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
out:
return (err);
@@ -728,13 +727,17 @@ int
ntlmssp_init_client(struct ssp_ctx *sp)
{
ntlmssp_state_t *ssp_st;
+ smb_ctx_t *ctx = sp->smb_ctx;
- if ((sp->smb_ctx->ct_authflags &
+ if ((ctx->ct_authflags &
(SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
DPRINT("No NTLM authflags");
return (EINVAL);
}
+ /* Get the client nonce. */
+ (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+
ssp_st = calloc(1, sizeof (*ssp_st));
if (ssp_st == NULL)
return (ENOMEM);
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
index c59bef81b4..698dd8359f 100644
--- a/usr/src/lib/libsmbfs/smb/print.c
+++ b/usr/src/lib/libsmbfs/smb/print.c
@@ -1,5 +1,4 @@
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, Boris Popov
* All rights reserved.
*
@@ -33,6 +32,10 @@
* $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
@@ -54,12 +57,24 @@
#include "private.h"
+/*
+ * Replacing invalid characters in print job titles:
+ *
+ * The spec. is unclear about what characters are allowed in a
+ * print job title (used with NtCreate) so out of caution this
+ * makes sure the title contains none of the characters that
+ * are known to be illegal in a file name component.
+ */
+static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
+
int
smb_open_printer(struct smb_ctx *ctx, const char *title,
int setuplen, int mode)
{
smbioc_printjob_t ioc;
- int err, tlen, new_fd;
+ char *p;
+ int err, tlen;
+ int new_fd = -1;
int32_t from_fd;
tlen = strlen(title);
@@ -75,7 +90,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
if (new_fd < 0)
return (errno);
from_fd = ctx->ct_dev_fd;
- if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
err = errno;
goto errout;
}
@@ -88,7 +103,15 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
ioc.ioc_prmode = mode;
strlcpy(ioc.ioc_title, title, SMBIOC_MAX_NAME);
- if (ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
+ /*
+ * The title is used in NtCreate so sanitize by
+ * replacing any illegal chars with spaces.
+ */
+ for (p = ioc.ioc_title; *p != '\0'; p++)
+ if (strchr(invalid_chars, *p) != NULL)
+ *p = ' ';
+
+ if (nsmb_ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -96,7 +119,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
return (new_fd);
errout:
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
diff --git a/usr/src/lib/libsmbfs/smb/private.h b/usr/src/lib/libsmbfs/smb/private.h
index febca40126..d877cafa1d 100644
--- a/usr/src/lib/libsmbfs/smb/private.h
+++ b/usr/src/lib/libsmbfs/smb/private.h
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _PRIVATE_H
@@ -61,60 +62,6 @@ extern void dprint(const char *, const char *, ...)
#endif
/*
- * Flags bits in ct_vcflags (copied from smb_conn.h)
- * Pass these to the driver?
- */
-#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */
-#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */
-#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
-#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
-#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
-#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
-
-/*
- * request handling structures
- */
-struct smb_rq {
- struct smb_ctx *rq_ctx;
- struct mbdata rq_rq;
- struct mbdata rq_rp;
- int rq_rpbufsz;
- uint8_t rq_cmd;
- uint8_t rq_hflags;
- uint16_t rq_hflags2;
- uint32_t rq_status;
- uint16_t rq_uid;
- uint16_t rq_tid;
- uint16_t rq_mid;
- uint32_t rq_seqno;
- /* See rq_[bw]{start,end} functions */
- char *rq_wcntp;
- int rq_wcbase;
- char *rq_bcntp;
- int rq_bcbase;
-};
-typedef struct smb_rq smb_rq_t;
-
-#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq)
-#define smb_rq_getreply(rqp) (&(rqp)->rq_rp)
-
-int smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **);
-void smb_rq_done(struct smb_rq *);
-void smb_rq_bstart(struct smb_rq *);
-void smb_rq_bend(struct smb_rq *);
-void smb_rq_wstart(struct smb_rq *);
-void smb_rq_wend(struct smb_rq *);
-int smb_rq_simple(struct smb_rq *);
-int smb_rq_dmem(struct mbdata *, const char *, size_t);
-int smb_rq_internal(struct smb_ctx *, struct smb_rq *);
-void smb_rq_sign(struct smb_rq *);
-int smb_rq_verify(struct smb_rq *);
-int smb_t2_request(int, int, uint16_t *, const char *,
- int, void *, int, void *, int *, void *, int *, void *, int *);
-
-/*
* This library extends the mchain.h function set a little.
*/
int m_getm(struct mbuf *, int, struct mbuf **);
@@ -174,16 +121,7 @@ int smb_ctx_getaddr(struct smb_ctx *ctx);
int smb_ctx_gethandle(struct smb_ctx *ctx);
int smb_iod_start(struct smb_ctx *);
-
-int smb_ssn_send(struct smb_ctx *, struct mbdata *);
-int smb_ssn_recv(struct smb_ctx *, struct mbdata *);
-
-int smb_negprot(struct smb_ctx *, struct mbdata *);
-
-int smb_ssnsetup_null(struct smb_ctx *);
-int smb_ssnsetup_ntlm1(struct smb_ctx *);
-int smb_ssnsetup_ntlm2(struct smb_ctx *);
-int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
+const char *smb_iod_state_name(enum smbiod_state st);
void smb_time_local2server(struct timeval *, int, long *);
void smb_time_server2local(ulong_t, int, struct timeval *);
diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c
deleted file mode 100644
index 546ee46f05..0000000000
--- a/usr/src/lib/libsmbfs/smb/rap.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
- *
- * This is very simple implementation of RAP protocol.
- */
-
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <sys/isa_defs.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <libintl.h>
-#include <sysexits.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-#include "private.h"
-
-static int
-smb_rap_parserqparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'L':
- case 'T':
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- len = 4;
- break;
- case 'b':
- case 'F':
- len = 1;
- break;
- case 'r':
- case 's':
- len = 0;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len = 0;
-
- switch (*s++) {
- case 'e':
- case 'h':
- len = 2;
- break;
- case 'i':
- len = 4;
- break;
- case 'g':
- len = 1;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpdata(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'B':
- len = 1;
- break;
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- case 'z':
- len = 4;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
-{
- int len = strlen(value) + 1;
-
- bcopy(value, rap->r_npbuf, len);
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-/*
- * Marshal RAP request parameters.
- * Note: value is in host order.
- */
-static int
-smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
-{
- int len = 0;
- uint_t uv = (uint_t)value;
- uint32_t *lp;
- uint16_t *sp;
- char *p;
-
- switch (ptype) {
- case 'L':
- case 'W':
- /* LINTED */
- sp = (uint16_t *)rap->r_npbuf;
- *sp = htoles(uv);
- len = sizeof (*sp);
- break;
- case 'D':
- /* LINTED */
- lp = (uint32_t *)rap->r_npbuf;
- *lp = htolel(uv);
- len = sizeof (*lp);
- break;
- case 'b':
- p = rap->r_npbuf;
- memset(p, uv, plen);
- len = plen;
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-int
-smb_rap_create(int fn, const char *param, const char *data,
- struct smb_rap **rapp)
-{
- struct smb_rap *rap;
- char *p;
- int plen = 0, len = 0;
-
- rap = malloc(sizeof (*rap));
- if (rap == NULL)
- return (ENOMEM);
- bzero(rap, sizeof (*rap));
- p = rap->r_sparam = rap->r_nparam = strdup(param);
- rap->r_sdata = rap->r_ndata = strdup(data);
-
- /*
- * Calculate length of request parameter block
- */
- len = 2 + strlen(param) + 1 + strlen(data) + 1;
- while (*p) {
- if (smb_rap_parserqparam(p, &p, &plen) != 0)
- break;
- len += plen;
- }
- rap->r_pbuf = rap->r_npbuf = malloc(len);
- if (rap->r_pbuf == NULL)
- return (ENOMEM);
- (void) smb_rap_rqparam(rap, 'W', 1, fn);
- (void) smb_rap_rqparam_z(rap, rap->r_sparam);
- (void) smb_rap_rqparam_z(rap, rap->r_sdata);
- *rapp = rap;
- return (0);
-}
-
-void
-smb_rap_done(struct smb_rap *rap)
-{
- if (rap->r_sparam)
- free(rap->r_sparam);
- if (rap->r_sdata)
- free(rap->r_sdata);
- if (rap->r_pbuf)
- free(rap->r_pbuf);
-#ifdef NOTYETDEFINED
- if (rap->r_npbuf)
- free(rap->r_npbuf);
- if (rap->r_dbuf)
- free(rap->r_dbuf);
- if (rap->r_rcvbuf)
- free(rap->r_rcvbuf);
-#endif
- free(rap);
-}
-
-int
-smb_rap_setNparam(struct smb_rap *rap, int value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'L':
- rap->r_rcvbuflen = value;
- /* FALLTHROUGH */
- case 'W':
- case 'D':
- case 'b':
- error = smb_rap_rqparam(rap, ptype, plen, value);
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_setPparam(struct smb_rap *rap, void *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'r':
- rap->r_rcvbuf = value;
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_getNparam(struct smb_rap *rap, long *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
- uint16_t *te;
-
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'h':
- /* LINTED */
- te = (uint16_t *)rap->r_npbuf;
- *value = letohs(*te);
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += plen;
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
-{
- uint16_t *rp, conv, *tmp;
- uint32_t *p32;
- char *dp, *p = rap->r_nparam;
- char ptype;
- int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
-
- rdatacnt = rap->r_rcvbuflen;
- rparamcnt = rap->r_plen;
- error = smb_t2_request(ctx->ct_dev_fd,
- 0, NULL, "\\PIPE\\LANMAN",
- rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
- 0, NULL, /* int tdatacnt, void *tdata */
- &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
- &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
- &buffer_oflow);
- if (error)
- return (error);
-
- /* LINTED */
- rp = (uint16_t *)rap->r_pbuf;
-
- /*
- * Note: First is a "LanMan API" error code.
- * See: usr/src/uts/common/smbsrv/lmerr.h
- */
- if (rparamcnt < 2)
- return (EBADRPC);
- rap->r_result = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- if (rap->r_result != 0) {
- /*
- * Could also return zero and let the caller
- * come get r_result via smb_rap_error(),
- * but in case they dont...
- */
- return (rap->r_result | SMB_RAP_ERROR);
- }
-
- if (rparamcnt < 2)
- return (EBADRPC);
- conv = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- rap->r_npbuf = (char *)rp;
- rap->r_entries = entries = 0;
- /* Save the returned data length */
- rap->r_rcvbuflen = rdatacnt;
- done = 0;
-
- while (!done && *p) {
- ptype = *p;
- switch (ptype) {
- case 'e':
- if (rparamcnt < 2)
- return (EBADRPC);
- /* LINTED */
- tmp = (uint16_t *)rap->r_npbuf;
- rap->r_entries = entries = letohs(*tmp);
- rap->r_npbuf += 2;
- rparamcnt -= 2;
- p++;
- break;
- default:
- done = 1;
- }
-#if 0 /* commented out in Darwin. Why? */
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply parameter mismatch %s"), 0, p);
- return (EBADRPC);
- }
-#endif
- }
- rap->r_nparam = p;
- /*
- * In general, unpacking entries we may need to relocate
- * entries for proper aligning. For now use them as is.
- */
- dp = rap->r_rcvbuf;
- while (entries--) {
- p = rap->r_sdata;
- while (*p) {
- ptype = *p;
- error = smb_rap_parserpdata(p, &p, &dlen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply data mismatch %s"), 0, p);
- return (EBADRPC);
- }
- if (rdatacnt < dlen)
- return (EBADRPC);
- switch (ptype) {
- case 'z':
- /* LINTED */
- p32 = (uint32_t *)dp;
- *p32 = (letohl(*p32) & 0xffff) - conv;
- break;
- }
- dp += dlen;
- rdatacnt -= dlen;
- }
- }
- return (error);
-}
-
-int
-smb_rap_error(struct smb_rap *rap, int error)
-{
- if (error)
- return (error);
- if (rap->r_result == 0)
- return (0);
- return (rap->r_result | SMB_RAP_ERROR);
-}
diff --git a/usr/src/lib/libsmbfs/smb/rc_scf.c b/usr/src/lib/libsmbfs/smb/rc_scf.c
new file mode 100644
index 0000000000..477982c0c8
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rc_scf.c
@@ -0,0 +1,231 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Support functions for getting things libsmbfs needs
+ * from the SMF configuration (using libscf).
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libscf.h>
+
+#include <cflib.h>
+#include "rcfile_priv.h"
+
+#define IDMAP_SERVICE_FMRI "svc:/system/idmap"
+#define IDMAP_PG_NAME "config"
+#define MACHINE_UUID "machine_uuid"
+
+#define SMBC_DEFAULT_INSTANCE_FMRI "svc:/network/smb/client:default"
+
+scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver);
+
+/*
+ * Get the "machine_uuid" from idmap, as a string (allocated)
+ */
+char *
+cf_get_client_uuid(void)
+{
+ char val_buf[64];
+ char *ret = NULL;
+
+ scf_handle_t *h = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *val = NULL;
+
+ if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
+ goto out;
+
+ if ((svc = scf_service_create(h)) == NULL ||
+ (pg = scf_pg_create(h)) == NULL ||
+ (prop = scf_property_create(h)) == NULL ||
+ (val = scf_value_create(h)) == NULL)
+ goto out;
+
+ if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI,
+ NULL, svc, NULL, NULL, NULL, 0) == -1)
+ goto out;
+
+
+ if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0)
+ goto out;
+ if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0)
+ goto out;
+ if (scf_property_get_value(prop, val) != 0)
+ goto out;
+ if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0)
+ goto out;
+
+ ret = strdup(val_buf);
+
+out:
+ scf_value_destroy(val);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_service_destroy(svc);
+
+ if (h != NULL)
+ scf_handle_destroy(h);
+
+ return (ret);
+}
+
+/*
+ * Get the output of "sharectl get smbfs" into a file, without an
+ * actual fork/exec of sharectl.
+ *
+ * Each section of the smbfs settings are represented as an SMF
+ * property group with an "S-" prefix and a UUID, and the section
+ * name itself a property which can have a more flexible name than
+ * a property group name can have.
+ */
+int
+rc_scf_get_sharectl(FILE *fp)
+{
+ char sect_name[256];
+ char prop_name[256];
+ char val_buf[1024];
+
+ scf_handle_t *h = NULL;
+ scf_service_t *svc = NULL;
+ scf_instance_t *inst = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *val = NULL;
+ scf_iter_t *pgiter = NULL;
+ scf_iter_t *propiter = NULL;
+ scf_iter_t *valiter = NULL;
+ int ret = -1;
+
+ if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
+ goto out;
+
+ if ((svc = scf_service_create(h)) == NULL ||
+ (inst = scf_instance_create(h)) == NULL ||
+ (pgiter = scf_iter_create(h)) == NULL ||
+ (propiter = scf_iter_create(h)) == NULL ||
+ (valiter = scf_iter_create(h)) == NULL ||
+ (pg = scf_pg_create(h)) == NULL ||
+ (prop = scf_property_create(h)) == NULL ||
+ (val = scf_value_create(h)) == NULL)
+ goto out;
+
+ if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI,
+ NULL, svc, inst, NULL, NULL, 0) == -1)
+ goto out;
+
+ if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1)
+ goto out;
+ while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) {
+ /*
+ * Using prop_name array for pg name temporarily.
+ * Skip any property groups names other than "S-*".
+ */
+ if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0)
+ continue;
+ if (strncmp(prop_name, "S-", 2) != 0)
+ continue;
+
+ /*
+ * Get the "section" name, which is a property of
+ * this property group.
+ */
+ if (scf_pg_get_property(pg, "section", prop) != 0)
+ continue;
+ if (scf_property_get_value(prop, val) != 0)
+ continue;
+ if (scf_value_get_as_string(val, sect_name,
+ sizeof (sect_name)) < 0)
+ continue;
+
+ /*
+ * Have an S-* property group with a "section" name.
+ * Print the section start.
+ */
+ fprintf(fp, "[%s]\n", sect_name);
+
+ /*
+ * Now print the remaining properties in this PG,
+ * but skip the special "section" (name) prop.
+ */
+ if (scf_iter_pg_properties(propiter, pg) == -1)
+ goto out;
+ while ((ret = scf_iter_next_property(propiter, prop)) == 1) {
+
+ if (scf_property_get_name(prop, prop_name,
+ sizeof (prop_name)) < 0)
+ continue;
+
+ /* Skip the "section" prop. now */
+ if (strcmp(prop_name, "section") == 0)
+ continue;
+
+ if (scf_property_get_value(prop, val) != 0)
+ continue;
+
+ if (scf_value_get_as_string(val, val_buf,
+ sizeof (val_buf)) < 0)
+ continue;
+
+ fprintf(fp, "%s=%s\n", prop_name, val_buf);
+ }
+ }
+ ret = 0;
+
+out:
+ fflush(fp);
+
+ scf_value_destroy(val);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_iter_destroy(valiter);
+ scf_iter_destroy(propiter);
+ scf_iter_destroy(pgiter);
+ scf_instance_destroy(inst);
+ scf_service_destroy(svc);
+
+ if (h != NULL)
+ scf_handle_destroy(h);
+
+ return (ret);
+}
+
+/*
+ * Simple test wrapper. Compile with:
+ * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf
+ */
+#ifdef TEST_MAIN
+int
+main(int argc, char **arv)
+{
+ char *s;
+ int rc;
+
+ rc = rc_scf_get_sharectl(stdout);
+ printf("# rc=%d\n", rc);
+ return (0);
+}
+#endif /* TEST_MAIN */
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
index 22ca0fc420..d7ee2d15af 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile.c
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -31,6 +31,9 @@
*
* $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
#include <fcntl.h>
#include <sys/types.h>
@@ -57,7 +60,6 @@
#define SMB_CFG_FILE "/etc/nsmb.conf"
#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf"
#endif
-#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs"
extern int smb_debug;
@@ -147,37 +149,77 @@ rc_merge(const char *filename, struct rcfile **rcfile)
}
/*
- * Like rc_open, but does popen of command:
- * sharectl get smbfs
+ * Like rc_open, but creates a temporary file and
+ * reads the sharectl settings into it.
+ * The file is deleted when we close it.
*/
static int
-rc_popen_cmd(const char *command, struct rcfile **rcfile)
+rc_open_sharectl(struct rcfile **rcfile)
{
- struct rcfile *rcp;
- FILE *f;
+ static char template[24] = "/tmp/smbfsXXXXXX";
+ struct rcfile *rcp = NULL;
+ FILE *fp = NULL;
+ int err;
+ int fd = -1;
assert(MUTEX_HELD(&rcfile_mutex));
- f = popen(command, "r");
- if (f == NULL)
- return (errno);
- insecure_nsmbrc = 0;
+ fd = mkstemp(template);
+ if (fd < 0) {
+ err = errno;
+ goto errout;
+ }
+
+ fp = fdopen(fd, "w+");
+ if (fp == NULL) {
+ err = errno;
+ close(fd);
+ goto errout;
+ }
+ fd = -1; /* The fp owns this fd now. */
+
+ /*
+ * Get smbfs sharectl settings into the file.
+ */
+ if ((err = rc_scf_get_sharectl(fp)) != 0)
+ goto errout;
rcp = malloc(sizeof (struct rcfile));
if (rcp == NULL) {
- fclose(f);
- return (ENOMEM);
+ err = ENOMEM;
+ goto errout;
}
bzero(rcp, sizeof (struct rcfile));
- rcp->rf_name = strdup(command);
- rcp->rf_f = f;
+
+ rcp->rf_name = strdup(template);
+ if (rcp->rf_name == NULL) {
+ err = ENOMEM;
+ goto errout;
+ }
+ rcp->rf_f = fp;
+ rcp->rf_flags = RCFILE_DELETE_ON_CLOSE;
+
SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ insecure_nsmbrc = 0;
rc_parse(rcp);
*rcfile = rcp;
/* fclose(f) in rc_close */
return (0);
+
+errout:
+ if (rcp != NULL)
+ free(rcp);
+ if (fp != NULL) {
+ fclose(fp);
+ fd = -1;
+ }
+ if (fd != -1)
+ close(fd);
+
+ return (err);
}
+
static int
rc_close(struct rcfile *rcp)
{
@@ -186,6 +228,9 @@ rc_close(struct rcfile *rcp)
mutex_lock(&rcfile_mutex);
fclose(rcp->rf_f);
+ if (rcp->rf_flags & RCFILE_DELETE_ON_CLOSE)
+ (void) unlink(rcp->rf_name);
+
for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
n = p;
p = SLIST_NEXT(p, rs_next);
@@ -343,11 +388,10 @@ set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
{
int now, new;
#ifdef DEBUG
- char *from;
+ char *from = "SMF";
- if (smb_debug)
- from = (home_nsmbrc) ?
- "user file" : "SMF";
+ if (home_nsmbrc != 0)
+ from = "user file";
#endif
if (strcmp(rkp->rk_name, "minauth") == 0) {
@@ -485,7 +529,7 @@ rc_parse(struct rcfile *rcp)
set_value(rcp, rsp, rkp, buf);
state = stNewLine;
rkp = NULL;
- } /* while */
+ } /* while */
if (c == EOF && state == stGetValue) {
*next = 0;
set_value(rcp, rsp, rkp, buf);
@@ -661,8 +705,8 @@ smb_open_rcfile(char *home)
fn = SMB_CFG_FILE;
error = rc_open(fn, &smb_rc);
#else
- fn = SMBFS_SHARECTL_CMD;
- error = rc_popen_cmd(fn, &smb_rc);
+ fn = "(sharectl get smbfs)";
+ error = rc_open_sharectl(&smb_rc);
#endif
if (error != 0 && error != ENOENT) {
/* Error from fopen. strerror is OK. */
diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
index ef9e31d7fc..b239c77a67 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
@@ -30,9 +30,26 @@
* SUCH DAMAGE.
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _RCFILE_PRIV_H
+#define _RCFILE_PRIV_H
+
+/*
+ * Private RC file support.
+ */
+
+#include <sys/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct rckey {
SLIST_ENTRY(rckey) rk_next;
- char *rk_name;
+ char *rk_name;
char *rk_value;
};
@@ -52,3 +69,12 @@ struct rcfile {
#define RCFILE_HOME_NSMBRC 1
#define RCFILE_IS_INSECURE 2
+#define RCFILE_DELETE_ON_CLOSE 4
+
+int rc_scf_get_sharectl(FILE *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RCFILE_PRIV_H */
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
deleted file mode 100644
index c4e929eff9..0000000000
--- a/usr/src/lib/libsmbfs/smb/rq.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <libintl.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include "private.h"
-
-#define MIN_REPLY_SIZE 4096
-
-static uint32_t smb_map_doserr(uint8_t, uint16_t);
-
-/*
- * Create and initialize a request structure, for either an
- * "internal" request (one that does not use the driver) or
- * a regular "driver" request, that uses driver ioctls.
- *
- * The two kinds are built a little differently:
- * Driver requests are composed starting with the
- * first word of the "variable word vector" section.
- * The driver prepends the SMB header and word count.
- * The driver also needs an output buffer to receive
- * the response, filled in via copyout in the ioctl.
- *
- * Internal requests are composed entirely in this library.
- * Space for the SMB header is reserved here, and later
- * filled in by smb_rq_internal before the send/receive.
- */
-int
-smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
-{
- struct smb_rq *rqp;
-
- rqp = malloc(sizeof (*rqp));
- if (rqp == NULL)
- goto errout;
- bzero(rqp, sizeof (*rqp));
- rqp->rq_cmd = cmd;
- rqp->rq_ctx = ctx;
-
- /*
- * Setup the request buffer.
- * Do the reply buffer later.
- */
- if (mb_init(&rqp->rq_rq))
- goto errout;
-
- /* Space for the SMB header. (filled in later) */
- mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
-
- /*
- * Copy the ctx flags here, so the caller can
- * update the req flags before the OTW call.
- */
- rqp->rq_hflags = ctx->ct_hflags;
- rqp->rq_hflags2 = ctx->ct_hflags2;
-
- *rqpp = rqp;
- return (0);
-
-errout:
- if (rqp) {
- smb_rq_done(rqp);
- free(rqp);
- }
- return (ENOMEM);
-}
-
-void
-smb_rq_done(struct smb_rq *rqp)
-{
- mb_done(&rqp->rq_rp);
- mb_done(&rqp->rq_rq);
- free(rqp);
-}
-
-/*
- * Reserve space for the word count, which is filled in later by
- * smb_rq_wend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the word count happens to be 8-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_wstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 1, &rqp->rq_wcntp);
- rqp->rq_wcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the word count, in the space reserved by
- * smb_rq_wstart().
- */
-void
-smb_rq_wend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int wcnt;
-
- if (rqp->rq_wcntp == NULL) {
- DPRINT("no wcount ptr\n");
- return;
- }
- wcnt = mbp->mb_count - rqp->rq_wcbase;
- if (wcnt > 0x1ff)
- DPRINT("word count too large (%d)\n", wcnt);
- if (wcnt & 1)
- DPRINT("odd word count\n");
- wcnt >>= 1;
-
- /*
- * Fill in the word count (8-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- */
- *rqp->rq_wcntp = (char)wcnt;
-}
-
-/*
- * Reserve space for the byte count, which is filled in later by
- * smb_rq_bend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the byte count happens to be 16-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_bstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 2, &rqp->rq_bcntp);
- rqp->rq_bcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the byte count, in the space reserved by
- * smb_rq_bstart().
- */
-void
-smb_rq_bend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int bcnt;
-
- if (rqp->rq_bcntp == NULL) {
- DPRINT("no bcount ptr\n");
- return;
- }
- bcnt = mbp->mb_count - rqp->rq_bcbase;
- if (bcnt > 0xffff)
- DPRINT("byte count too large (%d)\n", bcnt);
- /*
- * Fill in the byte count (16-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- *
- * The pointer is char * type due to
- * typical off-by-one alignment.
- */
- rqp->rq_bcntp[0] = bcnt & 0xFF;
- rqp->rq_bcntp[1] = (bcnt >> 8);
-}
-
-int
-smb_rq_simple(struct smb_rq *rqp)
-{
- struct smbioc_rq krq;
- struct mbdata *mbp;
- mbuf_t *m;
- char *data;
- uint32_t len;
- size_t rpbufsz;
- int error;
-
- bzero(&krq, sizeof (krq));
- krq.ioc_cmd = rqp->rq_cmd;
-
- /*
- * Make the SMB request body contiguous,
- * and fill in the ioctl request.
- */
- mbp = smb_rq_getrequest(rqp);
- error = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (error)
- return (error);
-
- data = mtod(mbp->mb_top, char *);
- len = m_totlen(mbp->mb_top);
-
- /*
- * _rq_init left space for the SMB header,
- * which makes mb_count the offset from
- * the beginning of the header (useful).
- * However, in this code path the driver
- * prepends the header, so we skip it.
- */
- krq.ioc_tbufsz = len - SMB_HDRLEN;
- krq.ioc_tbuf = data + SMB_HDRLEN;
-
- /*
- * Setup a buffer to hold the reply,
- * at least MIN_REPLY_SIZE, or larger
- * if the caller increased rq_rpbufsz.
- */
- mbp = smb_rq_getreply(rqp);
- rpbufsz = rqp->rq_rpbufsz;
- if (rpbufsz < MIN_REPLY_SIZE)
- rpbufsz = MIN_REPLY_SIZE;
- if ((error = m_get(rpbufsz, &m)) != 0)
- return (error);
- mb_initm(mbp, m);
- krq.ioc_rbufsz = rpbufsz;
- krq.ioc_rbuf = mtod(m, char *);
-
- /*
- * Call the driver
- */
- if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
- return (errno);
-
- /*
- * Initialize returned mbdata.
- * SMB header already parsed.
- */
- m->m_len = krq.ioc_rbufsz;
-
- return (0);
-}
-
-
-int
-smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
- const char *name,
- int tparamcnt, void *tparam,
- int tdatacnt, void *tdata,
- int *rparamcnt, void *rparam,
- int *rdatacnt, void *rdata,
- int *buffer_oflow)
-{
- smbioc_t2rq_t *krq;
- int i;
-
- krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
- bzero(krq, sizeof (*krq));
-
- if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
- /* Bogus setup count, or too many setup words */
- return (EINVAL);
- }
- for (i = 0; i < setupcount; i++)
- krq->ioc_setup[i] = setup[i];
- krq->ioc_setupcnt = setupcount;
- strcpy(krq->ioc_name, name);
- krq->ioc_tparamcnt = tparamcnt;
- krq->ioc_tparam = tparam;
- krq->ioc_tdatacnt = tdatacnt;
- krq->ioc_tdata = tdata;
-
- krq->ioc_rparamcnt = *rparamcnt;
- krq->ioc_rdatacnt = *rdatacnt;
- krq->ioc_rparam = rparam;
- krq->ioc_rdata = rdata;
-
- if (ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
- return (errno);
- }
-
- *rparamcnt = krq->ioc_rparamcnt;
- *rdatacnt = krq->ioc_rdatacnt;
- *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
- (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
- free(krq);
-
- return (0);
-}
-
-
-/*
- * Do an over-the-wire call without using the nsmb driver.
- * This is all "internal" to this library, and used only
- * for connection setup (negotiate protocol, etc.)
- */
-int
-smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
-{
- static const uint8_t ffsmb[4] = SMB_SIGNATURE;
- struct smb_iods *is = &ctx->ct_iods;
- uint32_t sigbuf[2];
- struct mbdata mbtmp, *mbp;
- int err, save_mlen;
- uint8_t ctmp;
-
- rqp->rq_uid = is->is_smbuid;
- rqp->rq_tid = SMB_TID_UNKNOWN;
- rqp->rq_mid = is->is_next_mid++;
-
- /*
- * Fill in the NBT and SMB headers
- * Using mbtmp so we can rewind without
- * affecting the passed request mbdata.
- */
- bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
- mbp = &mbtmp;
- mbp->mb_cur = mbp->mb_top;
- mbp->mb_pos = mbp->mb_cur->m_data;
- mbp->mb_count = 0;
- /* Have to save and restore m_len */
- save_mlen = mbp->mb_cur->m_len;
- mbp->mb_cur->m_len = 0;
-
- /*
- * rewind done; fill it in
- */
- mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
- mb_put_uint8(mbp, rqp->rq_cmd);
- mb_put_uint32le(mbp, 0); /* status */
- mb_put_uint8(mbp, rqp->rq_hflags);
- mb_put_uint16le(mbp, rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- mb_put_mem(mbp, NULL, 12, MB_MZERO);
- mb_put_uint16le(mbp, rqp->rq_tid);
- mb_put_uint16le(mbp, 0); /* pid_lo */
- mb_put_uint16le(mbp, rqp->rq_uid);
- mb_put_uint16le(mbp, rqp->rq_mid);
-
- /* Restore original m_len */
- mbp->mb_cur->m_len = save_mlen;
-
- /*
- * Sign the message, if flags2 indicates.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
-
- /*
- * Send it, wait for the reply.
- */
- if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
- return (err);
-
- if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
- return (err);
-
- /*
- * Should have an SMB header, at least.
- */
- mbp = &rqp->rq_rp;
- if (mbp->mb_cur->m_len < SMB_HDRLEN) {
- DPRINT("len < 32");
- return (EBADRPC);
- }
-
- /*
- * If the request was signed, validate the
- * signature on the response.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- err = smb_rq_verify(rqp);
- if (err) {
- DPRINT("bad signature");
- return (err);
- }
- }
-
- /*
- * Decode the SMB header.
- */
- md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
- if (0 != bcmp(sigbuf, ffsmb, 4)) {
- DPRINT("not SMB");
- return (EBADRPC);
- }
- md_get_uint8(mbp, &ctmp); /* SMB cmd */
- md_get_uint32le(mbp, &rqp->rq_status);
- md_get_uint8(mbp, &rqp->rq_hflags);
- md_get_uint16le(mbp, &rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
- md_get_uint16le(mbp, &rqp->rq_tid);
- md_get_uint16le(mbp, NULL); /* pid_lo */
- md_get_uint16le(mbp, &rqp->rq_uid);
- md_get_uint16le(mbp, &rqp->rq_mid);
-
- /*
- * Figure out the status return.
- * Caller looks at rq_status.
- */
- if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
- uint16_t serr;
- uint8_t class;
-
- class = rqp->rq_status & 0xff;
- serr = rqp->rq_status >> 16;
- rqp->rq_status = smb_map_doserr(class, serr);
- }
-
- return (0);
-}
-
-/*
- * Map old DOS errors (etc.) to NT status codes.
- * We probably don't need this anymore, since
- * the oldest server we talk to is NT. But if
- * later find we do need this, add support here
- * for the DOS errors we care about.
- */
-static uint32_t
-smb_map_doserr(uint8_t class, uint16_t serr)
-{
- if (class == 0 && serr == 0)
- return (0);
-
- DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
- return (NT_STATUS_UNSUCCESSFUL);
-}
diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c
deleted file mode 100644
index 0e9c826bbd..0000000000
--- a/usr/src/lib/libsmbfs/smb/signing.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Signing support, using libmd
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-
-#include <sys/types.h>
-#include <sys/md5.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-
-#include "private.h"
-
-#define SMBSIGOFF 14 /* SMB signature offset */
-#define SMBSIGLEN 8 /* SMB signature length */
-
-/*
- * Set this to a small number to debug sequence numbers
- * that seem to get out of step.
- */
-#ifdef DEBUG
-int nsmb_signing_fudge = 4;
-#endif
-
-/*
- * Compute MD5 digest of packet data, using the stored MAC key.
- *
- * See similar code in the driver:
- * uts/common/fs/smbclnt/netsmb/smb_signing.c
- * and on the server side:
- * uts/common/fs/smbsrv/smb_signing.c
- */
-static int
-smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m,
- uint32_t seqno, uchar_t *signature)
-{
- MD5_CTX md5;
- uchar_t digest[MD5_DIGEST_LENGTH];
-
- /*
- * This union is a little bit of trickery to:
- * (1) get the sequence number int aligned, and
- * (2) reduce the number of digest calls, at the
- * cost of a copying 32 bytes instead of 8.
- * Both sides of this union are 2+32 bytes.
- */
- union {
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t raw[SMB_HDRLEN]; /* header length (32) */
- } r;
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
- uint32_t sig[2]; /* MAC signature, aligned! */
- uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
- } s;
- } smbhdr;
-
- if (m->m_len < SMB_HDRLEN)
- return (EIO);
- if (ctx->ct_mackey == NULL)
- return (EINVAL);
-
- /*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
- */
- bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN);
- smbhdr.s.sig[0] = htolel(seqno);
- smbhdr.s.sig[1] = 0;
-
- /*
- * Compute the MAC: MD5(concat(Key, message))
- */
- MD5Init(&md5);
-
- /* Digest the MAC Key */
- MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen);
-
- /* Digest the (copied) SMB header */
- MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN);
-
- /* Digest the rest of the first mbuf */
- if (m->m_len > SMB_HDRLEN) {
- MD5Update(&md5, m->m_data + SMB_HDRLEN,
- m->m_len - SMB_HDRLEN);
- }
- m = m->m_next;
-
- /* Digest rest of the SMB message. */
- while (m) {
- MD5Update(&md5, m->m_data, m->m_len);
- m = m->m_next;
- }
-
- /* Final */
- MD5Final(digest, &md5);
-
- /*
- * Finally, store the signature.
- * (first 8 bytes of the digest)
- */
- if (signature)
- bcopy(digest, signature, SMBSIGLEN);
-
- return (0);
-}
-
-/*
- * Sign a request with HMAC-MD5.
- */
-void
-smb_rq_sign(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rq.mb_top;
- uint8_t *sigloc;
- int err;
-
- /*
- * Our mblk allocation ensures this,
- * but just in case...
- */
- if (m->m_len < SMB_HDRLEN)
- return;
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
-
- if (ctx->ct_mackey == NULL) {
- /*
- * Signing is required, but we have no key yet
- * fill in with the magic fake signing value.
- * This happens with SPNEGO, NTLMSSP, ...
- */
- bcopy("BSRSPLY", sigloc, 8);
- return;
- }
-
- /*
- * This will compute the MAC and store it
- * directly into the message at sigloc.
- */
- rqp->rq_seqno = ctx->ct_mac_seqno;
- ctx->ct_mac_seqno += 2;
- err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- bzero(sigloc, SMBSIGLEN);
- }
-}
-
-/*
- * Verify reply signature.
- */
-int
-smb_rq_verify(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rp.mb_top;
- uint8_t sigbuf[SMBSIGLEN];
- uint8_t *sigloc;
- uint32_t rseqno;
- int err, fudge;
-
- /*
- * Note ct_mackey and ct_mackeylen gets initialized by
- * smb_smb_ssnsetup. It's normal to have a null MAC key
- * during extended security session setup.
- */
- if (ctx->ct_mackey == NULL)
- return (0);
-
- /*
- * Let caller deal with empty reply or short messages by
- * returning zero. Caller will fail later, in parsing.
- */
- if (m == NULL) {
- DPRINT("empty reply");
- return (0);
- }
- if (m->m_len < SMB_HDRLEN) {
- DPRINT("short reply");
- return (0);
- }
-
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
- rseqno = rqp->rq_seqno + 1;
-
- DPRINT("rq_rseqno = 0x%x", rseqno);
-
- err = smb_compute_MAC(ctx, m, rseqno, sigbuf);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- /*
- * If we can't compute a MAC, then there's
- * no point trying other seqno values.
- */
- return (EBADRPC);
- }
-
- /*
- * Compare the computed signature with the
- * one found in the message (at sigloc)
- */
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- return (0);
-
- DPRINT("BAD signature, MID=0x%x", rqp->rq_mid);
-
-#ifdef DEBUG
- /*
- * For diag purposes, we check whether the client/server idea
- * of the sequence # has gotten a bit out of sync.
- */
- for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
- (void) smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- break;
- (void) smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
- fudge = -fudge;
- break;
- }
- }
- if (fudge <= nsmb_signing_fudge) {
- DPRINT("rseqno=%d, but %d would have worked",
- rseqno, rseqno + fudge);
- }
-#endif
- return (EBADRPC);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
deleted file mode 100644
index da7640241c..0000000000
--- a/usr/src/lib/libsmbfs/smb/ssnsetup.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Session Setup, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/netbios.h>
-#include <netsmb/smb_dev.h>
-#include <netsmb/smb.h>
-
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-
-#include "private.h"
-#include "charsets.h"
-#include "ntlm.h"
-#include "smb_crypt.h"
-
-
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp);
-
-/*
- * Session Setup: NULL session (anonymous)
- */
-int
-smb_ssnsetup_null(struct smb_ctx *ctx)
-{
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- return (err);
-}
-
-
-/*
- * SMB Session Setup, using NTLMv1 (and maybe LMv1)
- */
-int
-smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
-
- /* Put the LM,NTLM responses (as mbdata). */
- err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-/*
- * SMB Session Setup, using NTLMv2 (and LMv2)
- */
-int
-smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc, ti_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
- bzero(&ti_mbc, sizeof (ti_mbc));
-
- /* Build the NTLMv2 "target info" blob (as mbdata) */
- err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
- if (err)
- goto out;
-
- /* Put the LMv2, NTLMv2 responses (as mbdata). */
- err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&ti_mbc);
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-int
-smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
-{
- struct mbdata send_mb, recv_mb;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- err = ssp_ctx_create_client(ctx, hint_mb);
- if (err)
- goto out;
-
- bzero(&send_mb, sizeof (send_mb));
- bzero(&recv_mb, sizeof (recv_mb));
-
- /* NULL input indicates first call. */
- err = ssp_ctx_next_token(ctx, NULL, &send_mb);
- if (err)
- goto out;
-
- for (;;) {
- err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
- &ntstatus, &action);
- if (err)
- goto out;
- if (ntstatus == 0)
- break; /* normal loop termination */
- if (ntstatus != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- err = EAUTH;
- goto out;
- }
-
- /* middle calls get both in, out */
- err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
- if (err)
- goto out;
- }
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
-
- /* NULL output indicates last call. */
- (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
-
-out:
- ssp_ctx_destroy(ctx);
-
- return (err);
-}
-
-/*
- * Session Setup function used for all the forms we support.
- * To allow this sharing, the crypto stuff is computed by
- * callers and passed in as mbdata chains. Also, the args
- * have different meanings for extended security vs. old.
- * Some may be used as either IN or OUT parameters.
- *
- * For NTLM (v1, v2), all parameters are inputs
- * mbc1: [in] LM password hash
- * mbc2: [in] NT password hash
- * For Extended security (spnego)
- * mbc1: [in] outgoing blob data
- * mbc2: [out] received blob data
- * For both forms, these are optional:
- * statusp: [out] NT status
- * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
- */
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp)
-{
- static const char NativeOS[] = "Solaris";
- static const char LanMan[] = "NETSMB";
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp = NULL;
- struct mbdata *mbp;
- struct mbuf *m;
- int err, uc;
- uint32_t caps;
- uint16_t bc, len1, len2, sblen;
- uint8_t wc;
-
- caps = ctx->ct_clnt_caps;
- uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
-
- err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
- if (err)
- goto out;
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
- mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
- mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
- mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
- mb_put_uint16le(mbp, 1); /* 4: VcNumber */
- mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
-
- if (caps & SMB_CAP_EXT_SECURITY) {
- len1 = mbc1 ? mbc1->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */
- mb_put_uint32le(mbp, 0); /* 8,9: reserved */
- mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
- smb_rq_wend(rqp); /* 12: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */
- mbc1->mb_top = NULL; /* consumed */
- }
- /* mbc2 is required below */
- if (mbc2 == NULL) {
- err = EINVAL;
- goto out;
- }
- } else {
- len1 = mbc1 ? mbc1->mb_count : 0;
- len2 = mbc2 ? mbc2->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: LM pass. len */
- mb_put_uint16le(mbp, len2); /* 8: NT pass. len */
- mb_put_uint32le(mbp, 0); /* 9,10: reserved */
- mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */
- smb_rq_wend(rqp); /* 13: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */
- mbc1->mb_top = NULL; /* consumed */
- }
- if (mbc2 && mbc2->mb_top) {
- mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */
- mbc2->mb_top = NULL; /* consumed */
- }
- mb_put_string(mbp, ctx->ct_user, uc);
- mb_put_string(mbp, ctx->ct_domain, uc);
- }
- mb_put_string(mbp, NativeOS, uc);
- mb_put_string(mbp, LanMan, uc);
- smb_rq_bend(rqp);
-
- err = smb_rq_internal(ctx, rqp);
- if (err)
- goto out;
-
- if (statusp)
- *statusp = rqp->rq_status;
-
- /*
- * If we have a real error, the response probably has
- * no more data, so don't try to parse any more.
- * Note: err=0, means rq_status is valid.
- */
- if (rqp->rq_status != 0 &&
- rqp->rq_status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- goto out;
- }
-
- /*
- * Parse the reply
- */
- uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
- is->is_smbuid = rqp->rq_uid;
- mbp = &rqp->rq_rp;
-
- err = md_get_uint8(mbp, &wc);
- if (err)
- goto out;
-
- err = EBADRPC; /* for any problems in this section */
- if (caps & SMB_CAP_EXT_SECURITY) {
- if (wc != 4)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- md_get_uint16le(mbp, &sblen); /* sec. blob len */
- md_get_uint16le(mbp, &bc); /* byte count */
- /*
- * Get the security blob, after
- * sanity-checking the length.
- */
- if (sblen == 0 || bc < sblen)
- goto out;
- err = md_get_mbuf(mbp, sblen, &m);
- if (err)
- goto out;
- mb_initm(mbc2, m);
- mbc2->mb_count = sblen;
- } else {
- if (wc != 3)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- err = md_get_uint16le(mbp, &bc); /* byte count */
- if (err)
- goto out;
- }
-
- /*
- * Native OS, LANMGR, & Domain follow here.
- * Parse these strings and store for later.
- * If unicode, they should be aligned.
- *
- * Note that with Extended security, we may use
- * multiple calls to this function. Only parse
- * these strings on the last one (status == 0).
- * Ditto for the CAP_LARGE work-around.
- */
- if (rqp->rq_status != 0)
- goto out;
-
- /* Ignore any parsing errors for these strings. */
- err = md_get_string(mbp, &ctx->ct_srv_OS, uc);
- DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
- err = md_get_string(mbp, &ctx->ct_srv_LM, uc);
- DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
- /*
- * There's sometimes a server domain folloing
- * at this point, but we don't need it.
- */
-
- /* Success! (See Ignore any ... above) */
- err = 0;
-
- /*
- * MS-SMB 2.2.4.5 clarifies that when SMB signing is enabled,
- * the client should NOT use "large read/write" even though
- * the server might offer those capabilities.
- */
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- DPRINT("signing, so disable CAP_LARGE_(r/w)");
- ctx->ct_sopt.sv_caps &=
- ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
- }
-
-out:
- if (rqp)
- smb_rq_done(rqp);
-
- return (err);
-}
diff --git a/usr/src/lib/smbclnt/Makefile b/usr/src/lib/smbclnt/Makefile
new file mode 100644
index 0000000000..4425611834
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.lib
+
+SUBDIRS = \
+ libfknsmb \
+ libfksmbfs
+
+libfksmbfs: libfknsmb
+
+include ./Makefile.subdirs
diff --git a/usr/src/lib/smbclnt/Makefile.lib b/usr/src/lib/smbclnt/Makefile.lib
new file mode 100644
index 0000000000..67528308d3
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.lib
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Common Makefile definitions for smbclnt
+#
+
+# We reset the Makefile.lib macros ROOTLIBDIR to refer to usr/lib/smbfs.
+# For 64 bit, we reset ROOTLIBDIR64 to refer to usr/lib/smbfs/$(MACH64).
+# Install the userland library header files under /usr/include/netsmb
+ROOTSMBHDRDIR= $(ROOTHDRDIR)/netsmb
+ROOTSMBHDRS= $(HDRS:%=$(ROOTSMBHDRDIR)/%)
+
+ROOTLIBDIR = $(ROOT)/usr/lib/smbfs
+ROOTLIBDIR64 = $(ROOT)/usr/lib/smbfs/$(MACH64)
+
+SRCDIR= ../common
+LIBS= $(DYNLIB) $(LINTLIB)
+
+CSTD = $(CSTD_GNU99)
+
+CPPFLAGS += -I$(SRCDIR) -I.
+LDLIBS32 += -L$(ROOT)/usr/lib/smbfs
+LDLIBS64 += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CLEANFILES += $(OBJECTS:%_ndr.o=%_ndr.c)
diff --git a/usr/src/lib/smbclnt/Makefile.smbclnt b/usr/src/lib/smbclnt/Makefile.smbclnt
new file mode 100644
index 0000000000..4df97c6daa
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.smbclnt
@@ -0,0 +1,66 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Toplevel Makefile included by each subdirectory. Responsible for the 'check'
+# and 'install_h' targets, as well as descending into the architecture directory
+# to actually build the library.
+#
+
+include ../../Makefile.lib
+include ../Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+HDRDIR= common
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+install_h: $(ROOTSMBHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+FRC:
+
+$(ROOTSMBHDRDIR)/%: common/%
+ $(INS.file)
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/Makefile.subdirs b/usr/src/lib/smbclnt/Makefile.subdirs
new file mode 100644
index 0000000000..66720e53ee
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.subdirs
@@ -0,0 +1,43 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+.KEEP_STATE:
+
+all := TARGET = all
+check := TARGET = check
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+install_h := TARGET = install_h
+lint := TARGET = lint
+
+all check clean clobber install install_h lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/smbclnt/Makefile.targ b/usr/src/lib/smbclnt/Makefile.targ
new file mode 100644
index 0000000000..4c910e3565
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.targ
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Common targets for smbclnt Makefiles
+#
+
+pics/%.o: $(SRC)/common/smbclnt/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: # skip
+
+$(ROOTLIBS): $(ROOTLIBDIR)
+
+$(ROOTLIBDIR):
+ $(INS.dir)
+
+$(ROOTLIBS64): $(ROOTLIBDIR64)
+
+$(ROOTLIBDIR64):
+ $(INS.dir)
diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile b/usr/src/lib/smbclnt/libfknsmb/Makefile
new file mode 100644
index 0000000000..ee4ab9faf7
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.smbclnt
diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile.com b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
new file mode 100644
index 0000000000..01da52d337
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
@@ -0,0 +1,109 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+#
+
+LIBRARY = libfknsmb.a
+VERS = .1
+
+OBJS_LOCAL = \
+ fksmb_sign_pkcs.o \
+ fake_ddi.o \
+ fake_fio.o \
+ fake_kmem.o \
+ fake_ktli.o \
+ fake_pkey.o \
+ fake_policy.o \
+ fake_sdt.o \
+ fake_softc.o \
+ fake_stream.o \
+ fake_strsubr.o
+
+# See also: $SRC/uts/common/Makefile.files
+# NB: Intentionally ommitted, compared w/ the above:
+# smb_dev.o smb_pass.o smb_sign_kcf.o
+#
+OBJS_NSMB = \
+ smb_dev.o \
+ smb_conn.o \
+ smb_iod.o \
+ smb_rq.o \
+ smb_sign.o \
+ smb_smb.o \
+ smb_subrs.o \
+ smb_time.o \
+ smb_tran.o \
+ smb_trantcp.o \
+ smb_usr.o \
+ smb2_rq.o \
+ smb2_sign.o \
+ smb2_smb.o \
+ subr_mchain.o
+
+OBJECTS = \
+ $(OBJS_LOCAL) \
+ $(OBJS_NSMB)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+CPPFLAGS.first += -I../../../libfakekernel/common
+CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+
+CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CERRWARN += -_gcc=-Wno-switch
+
+LDLIBS += $(MACH_LDLIBS)
+LDLIBS += -lfakekernel -lpkcs11 -lnsl -lc
+
+NSMB_DIR=$(SRC)/uts/common/fs/smbclnt/netsmb
+SRCS= $(OBJS_LOCAL:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_NSMB:%.o=$(NSMB_DIR)/%.c)
+
+all:
+
+pics/%.o: $(NSMB_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile b/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile
new file mode 100644
index 0000000000..441f9285b5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile
@@ -0,0 +1,21 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c
new file mode 100644
index 0000000000..4dc0faf984
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c
@@ -0,0 +1,133 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * UNIX Device Driver Interface functions
+ * (excerpts)
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/ddi.h>
+#include <sys/mkdev.h>
+#include <sys/debug.h>
+
+#ifndef NODEV32
+#define NODEV32 (dev32_t)(-1)
+#endif /* NODEV32 */
+
+/*
+ * return internal major number corresponding to device
+ * number (new format) argument
+ */
+major_t
+getmajor(dev_t dev)
+{
+#ifdef _LP64
+ return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
+#else
+ return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
+#endif
+}
+
+/*
+ * return internal minor number corresponding to device
+ * number (new format) argument
+ */
+minor_t
+getminor(dev_t dev)
+{
+#ifdef _LP64
+ return ((minor_t)(dev & MAXMIN64));
+#else
+ return ((minor_t)(dev & MAXMIN));
+#endif
+}
+
+/*
+ * encode external major and minor number arguments into a
+ * new format device number
+ */
+dev_t
+makedevice(major_t maj, minor_t minor)
+{
+#ifdef _LP64
+ return (((dev_t)maj << NBITSMINOR64) | (minor & MAXMIN64));
+#else
+ return (((dev_t)maj << NBITSMINOR) | (minor & MAXMIN));
+#endif
+}
+
+/*
+ * Compress 'long' device number encoding to 32-bit device number
+ * encoding. If it won't fit, we return failure, but set the
+ * device number to 32-bit NODEV for the sake of our callers.
+ */
+int
+cmpldev(dev32_t *dst, dev_t dev)
+{
+#if defined(_LP64)
+ if (dev == NODEV) {
+ *dst = NODEV32;
+ } else {
+ major_t major = dev >> L_BITSMINOR;
+ minor_t minor = dev & L_MAXMIN;
+
+ if (major > L_MAXMAJ32 || minor > L_MAXMIN32) {
+ *dst = NODEV32;
+ return (0);
+ }
+
+ *dst = (dev32_t)((major << L_BITSMINOR32) | minor);
+ }
+#else
+ *dst = (dev32_t)dev;
+#endif
+ return (1);
+}
+
+/*
+ * Expand 32-bit dev_t's to long dev_t's. Expansion always "fits"
+ * into the return type, but we're careful to expand NODEV explicitly.
+ */
+dev_t
+expldev(dev32_t dev32)
+{
+#ifdef _LP64
+ if (dev32 == NODEV32)
+ return (NODEV);
+ return (makedevice((dev32 >> L_BITSMINOR32) & L_MAXMAJ32,
+ dev32 & L_MAXMIN32));
+#else
+ return ((dev_t)dev32);
+#endif
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c
new file mode 100644
index 0000000000..18f8fa2255
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * The kTLI "shim" over in ./fake_ktli.c uses getf(), releasef() to
+ * represent an open socket FD in "fake" vnode_t and file_t objects.
+ * This implements minimal getf()/releasef() shims for that purpose.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+
+#define FAKEFDS 256
+
+kmutex_t ftlock;
+file_t *ftab[FAKEFDS];
+
+file_t *
+getf(int fd)
+{
+ file_t *fp;
+ vnode_t *vp;
+
+ if (fd >= FAKEFDS)
+ return (NULL);
+
+ mutex_enter(&ftlock);
+ if ((fp = ftab[fd]) != NULL) {
+ fp->f_count++;
+ mutex_exit(&ftlock);
+ return (fp);
+ }
+
+ fp = kmem_zalloc(sizeof (*fp), KM_SLEEP);
+ vp = kmem_zalloc(sizeof (*vp), KM_SLEEP);
+ vp->v_fd = fd;
+ fp->f_vnode = vp;
+ fp->f_count = 1;
+ ftab[fd] = fp;
+
+ mutex_exit(&ftlock);
+
+ return (fp);
+}
+
+void
+releasef(int fd)
+{
+ file_t *fp;
+ vnode_t *vp;
+
+ mutex_enter(&ftlock);
+ if ((fp = ftab[fd]) == NULL) {
+ mutex_exit(&ftlock);
+ return;
+ }
+ fp->f_count--;
+ if (fp->f_count > 0) {
+ mutex_exit(&ftlock);
+ return;
+ }
+ ftab[fd] = NULL;
+ mutex_exit(&ftlock);
+
+ vp = fp->f_vnode;
+ kmem_free(vp, sizeof (*vp));
+ kmem_free(fp, sizeof (*fp));
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c
new file mode 100644
index 0000000000..21453f410d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+
+static size_t availmem = (1<<24);
+
+size_t
+kmem_avail(void)
+{
+ return (availmem);
+}
+
+size_t
+kmem_maxavail(void)
+{
+ return (availmem);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c
new file mode 100644
index 0000000000..3011de2e77
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c
@@ -0,0 +1,432 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Kernel TLI-like functions
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/filio.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/tihdr.h>
+#include <sys/timod.h>
+#include <sys/tiuser.h>
+#include <sys/t_kuser.h>
+
+#include <errno.h>
+#include <stropts.h>
+#include <unistd.h>
+
+#include "fake_xti.h"
+
+/* Size of mblks for tli_recv */
+#define FKTLI_RCV_SZ 4096
+
+/*
+ * Translate a TLI error into a system error as best we can.
+ */
+static const int tli_errs[] = {
+ 0, /* no error */
+ EADDRNOTAVAIL, /* TBADADDR */
+ ENOPROTOOPT, /* TBADOPT */
+ EACCES, /* TACCES */
+ EBADF, /* TBADF */
+ EADDRNOTAVAIL, /* TNOADDR */
+ EPROTO, /* TOUTSTATE */
+ EPROTO, /* TBADSEQ */
+ ENOSYS, /* TSYSERR */
+ EPROTO, /* TLOOK */
+ EMSGSIZE, /* TBADDATA */
+ EMSGSIZE, /* TBUFOVFLW */
+ EPROTO, /* TFLOW */
+ EWOULDBLOCK, /* TNODATA */
+ EPROTO, /* TNODIS */
+ EPROTO, /* TNOUDERR */
+ EINVAL, /* TBADFLAG */
+ EPROTO, /* TNOREL */
+ EOPNOTSUPP, /* TNOTSUPPORT */
+ EPROTO, /* TSTATECHNG */
+};
+
+static int
+tlitosyserr(int terr)
+{
+ if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))))
+ return (EPROTO);
+ else
+ return (tli_errs[terr]);
+}
+
+/*
+ * Note: This implementation is specific to the needs of the callers in
+ * uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+ */
+/* ARGSUSED */
+int
+t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
+{
+ boolean_t madefp = B_FALSE;
+ vnode_t *vp;
+ TIUSER *tiu;
+ int fd;
+ int rc;
+
+ *tiptr = NULL;
+
+ if (fp == NULL) {
+ /*
+ * create a socket endpoint
+ * dev is actualy AF
+ */
+ char *devnm;
+ switch (rdev) {
+ case AF_INET:
+ devnm = "/dev/tcp";
+ break;
+ case AF_INET6:
+ devnm = "/dev/tcp6";
+ break;
+ default:
+ cmn_err(CE_NOTE, "t_kopen: bad device");
+ return (EINVAL);
+ }
+
+ fd = t_open(devnm, O_RDWR, NULL);
+ if (fd < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kopen: t_open terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+
+ /*
+ * allocate a file pointer...
+ */
+ fp = getf(fd);
+ madefp = B_TRUE;
+ }
+ vp = fp->f_vnode;
+ fd = vp->v_fd;
+
+ tiu = kmem_zalloc(sizeof (*tiu), KM_SLEEP);
+ rc = t_getinfo(fd, &tiu->tp_info);
+ if (rc < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kopen: t_getinfo terr=%d", rc);
+ kmem_free(tiu, sizeof (*tiu));
+ if (madefp) {
+ releasef(fd);
+ (void) t_close(fd);
+ }
+ return (tlitosyserr(rc));
+ }
+
+ tiu->fp = fp;
+ tiu->flags = madefp ? MADE_FP : 0;
+ *tiptr = tiu;
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+t_kclose(TIUSER *tiptr, int callclosef)
+{
+ file_t *fp;
+
+ fp = (tiptr->flags & MADE_FP) ? tiptr->fp : NULL;
+
+ kmem_free(tiptr, TIUSERSZ);
+
+ if (fp != NULL) {
+ vnode_t *vp = fp->f_vnode;
+ int fd = vp->v_fd;
+ releasef(fd);
+ (void) t_close(fd);
+ }
+
+ return (0);
+}
+
+int
+t_kbind(TIUSER *tiptr, struct t_bind *req, struct t_bind *ret)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_bind(vp->v_fd, req, ret) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kbind: t_bind terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+int
+t_kunbind(TIUSER *tiptr)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_unbind(vp->v_fd) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kunbind: t_unbind terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+int
+t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_connect(vp->v_fd, sndcall, rcvcall) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kconnect: t_connect terr=%d", rc);
+ if (rc == TLOOK) {
+ /* Probably got a RST. */
+ rc = ECONNREFUSED;
+ } else {
+ rc = tlitosyserr(rc);
+ }
+ return (rc);
+ }
+ return (0);
+}
+
+int
+t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_optmgmt(vp->v_fd, req, ret) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_koptmgmt: t_optmgmt terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+/*
+ * Poll for an input event.
+ *
+ * timo is measured in ticks
+ */
+int
+t_kspoll(TIUSER *tiptr, int timo, int waitflg, int *events)
+{
+ struct pollfd pfds[1];
+ file_t *fp;
+ vnode_t *vp;
+ clock_t timout; /* milliseconds */
+ int n;
+
+ fp = tiptr->fp;
+ vp = fp->f_vnode;
+
+ if (events == NULL || ((waitflg & READWAIT) == 0))
+ return (EINVAL);
+
+ /* Convert from ticks to milliseconds */
+ if (timo < 0)
+ timout = -1;
+ else
+ timout = TICK_TO_MSEC(timo);
+
+ pfds[0].fd = vp->v_fd;
+ pfds[0].events = POLLIN;
+ pfds[0].revents = 0;
+
+ errno = 0;
+ n = poll(pfds, 1, timout);
+ if (n < 0)
+ return (errno);
+ if (n == 0)
+ return (ETIME);
+ *events = pfds[0].revents;
+ return (0);
+}
+
+/*
+ * Send the message, return zero or errno.
+ * Always free's the message, even on error.
+ */
+int
+tli_send(TIUSER *tiptr, mblk_t *bp, int fmode)
+{
+ struct strbuf ctlbuf;
+ struct strbuf databuf;
+ mblk_t *m;
+ int flg, n, rc;
+ vnode_t *vp;
+
+ if (bp == NULL)
+ return (0);
+ vp = tiptr->fp->f_vnode;
+
+ switch (bp->b_datap->db_type) {
+ case M_DATA:
+ for (m = bp; m != NULL; m = m->b_cont) {
+ n = MBLKL(m);
+ flg = (m->b_cont != NULL) ? T_MORE : 0;
+ rc = t_snd(vp->v_fd, (void *) m->b_rptr, n, flg);
+ if (rc != n) {
+ rc = EIO;
+ goto out;
+ }
+ }
+ rc = 0;
+ break;
+
+ /*
+ * May get M_PROTO/T_DISCON_REQ from nb_snddis()
+ */
+ case M_PROTO:
+ case M_PCPROTO:
+ ctlbuf.len = MBLKL(bp);
+ ctlbuf.maxlen = MBLKL(bp);
+ ctlbuf.buf = (char *)bp->b_rptr;
+ if (bp->b_cont == NULL) {
+ bzero(&databuf, sizeof (databuf));
+ } else {
+ m = bp->b_cont;
+ databuf.len = MBLKL(m);
+ databuf.maxlen = MBLKL(m);
+ databuf.buf = (char *)m->b_rptr;
+ }
+ if (putmsg(vp->v_fd, &ctlbuf, &databuf, 0) < 0) {
+ rc = errno;
+ cmn_err(CE_NOTE, "tli_send: putmsg err=%d", rc);
+ } else {
+ rc = 0;
+ }
+ break;
+
+ default:
+ rc = EIO;
+ break;
+ }
+
+out:
+ freemsg(bp);
+ return (rc);
+}
+
+int
+tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode)
+{
+ mblk_t *mtop = NULL;
+ mblk_t *m;
+ vnode_t *vp;
+ int error;
+ int flags;
+ int nread;
+ int n;
+
+ vp = tiptr->fp->f_vnode;
+
+
+
+ /*
+ * Get an mblk for the data
+ */
+ nread = FKTLI_RCV_SZ;
+ m = allocb_wait(nread, 0, 0, &error);
+ ASSERT(m != NULL);
+
+ if (mtop == NULL)
+ mtop = m;
+
+again:
+ flags = 0;
+ n = t_rcv(vp->v_fd, (void *) m->b_rptr, nread, &flags);
+ if (n < 0) {
+ n = t_errno;
+ cmn_err(CE_NOTE, "tli_recv: t_rcv terr=%d", n);
+ error = tlitosyserr(n);
+ goto errout;
+ }
+ if (n == 0) {
+ error = ENOTCONN;
+ goto errout;
+ }
+ ASSERT(n > 0 && n <= nread);
+ m->b_wptr = m->b_rptr + n;
+
+ if (flags & T_MORE) {
+ mblk_t *mtail = m;
+ m = allocb_wait(nread, 0, 0, &error);
+ ASSERT(m != NULL);
+ mtail->b_cont = m;
+ goto again;
+ }
+
+ *bp = mtop;
+ return (0);
+
+errout:
+ if (m == mtop) {
+ freemsg(mtop);
+ return (error);
+ }
+
+ /* got some data, so return it. */
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c
new file mode 100644
index 0000000000..b7944f8dca
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c
@@ -0,0 +1,48 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * pkey stubs
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/errno.h>
+
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_pass.h>
+
+void
+smb_pkey_init()
+{
+}
+
+void
+smb_pkey_fini()
+{
+}
+
+int
+smb_pkey_idle()
+{
+ return (0);
+}
+
+/* ARGSUSED */
+int
+smb_pkey_ioctl(int cmd, intptr_t arg, int flags, cred_t *cr)
+{
+ return (ENOTTY);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c
new file mode 100644
index 0000000000..4531e86bae
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/errno.h>
+#include <sys/policy.h>
+
+/* ARGSUSED */
+int
+secpolicy_fs_allowed_mount(const char *fsname)
+{
+ return (0);
+}
+
+int
+secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner,
+ mode_t curmode, mode_t wantmode)
+{
+ mode_t mode;
+
+ mode = ~curmode & wantmode;
+
+ if (mode == 0)
+ return (0);
+ return (EACCES);
+}
+
+int
+secpolicy_vnode_owner(const cred_t *cr, uid_t owner)
+{
+ /* cr->cr_uid */
+ if (owner == crgetruid(cr))
+ return (0);
+
+ return (EPERM);
+}
+
+int
+secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
+ const struct vattr *ovap, int flags,
+ int unlocked_access(void *, int, cred_t *),
+ void *node)
+{
+ int mask = vap->va_mask;
+
+ if (mask & AT_SIZE) {
+ if (vp->v_type == VDIR)
+ return (EISDIR);
+ }
+ if (mask & AT_MODE)
+ return (EACCES);
+ if (mask & (AT_UID|AT_GID))
+ return (EACCES);
+
+ return (0);
+}
+
+int
+secpolicy_vnode_setdac(const cred_t *cred, uid_t owner)
+{
+ if (owner == crgetuid(cred))
+ return (0);
+
+ return (EPERM);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c
new file mode 100644
index 0000000000..bc88864843
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+
+/*
+ * See: DTRACE_PROBE... in sys/sdt.h
+ */
+
+int fknsmb_dtrace_log = 0;
+
+void
+smb_dtrace1(const char *n, long v1)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace1: %s,"
+ " 0x%lx\n", n, v1);
+ }
+}
+
+void
+smb_dtrace2(const char *n, long v1, long v2)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace2: %s,"
+ " 0x%lx, 0x%lx\n", n, v1, v2);
+ }
+}
+
+void
+smb_dtrace3(const char *n, long v1, long v2, long v3)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace3: %s,"
+ " 0x%lx, 0x%lx, 0x%lx\n", n, v1, v2, v3);
+ }
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c
new file mode 100644
index 0000000000..2d990ed3f8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c
@@ -0,0 +1,263 @@
+
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/debug.h>
+#include <sys/sunddi.h>
+
+#define MIN_N_ITEMS 8
+
+typedef struct i_ddi_soft_state {
+ void **array; /* the array of pointers */
+ kmutex_t lock; /* serialize access to this struct */
+ size_t size; /* how many bytes per state struct */
+ size_t n_items; /* how many structs herein */
+ void *next; /* unused */
+} i_ddi_soft_state;
+
+
+void *
+ddi_get_soft_state(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void *ret = NULL;
+
+ ASSERT((ss != NULL) && (item >= 0));
+
+ mutex_enter(&ss->lock);
+
+ if (item < ss->n_items && ss->array != NULL)
+ ret = ss->array[item];
+
+ mutex_exit(&ss->lock);
+
+ return (ret);
+}
+
+
+int
+ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
+{
+ i_ddi_soft_state *ss;
+
+ if (state_p == NULL || size == 0)
+ return (EINVAL);
+
+ ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
+ mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
+ ss->size = size;
+
+ if (n_items < MIN_N_ITEMS)
+ ss->n_items = MIN_N_ITEMS;
+ else {
+ ss->n_items = n_items;
+ }
+
+ ASSERT(ss->n_items >= n_items);
+
+ ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
+
+ *state_p = ss;
+ return (0);
+}
+
+/*
+ * Allocate a state structure of size 'size' to be associated
+ * with item 'item'.
+ *
+ * In this implementation, the array is extended to
+ * allow the requested offset, if needed.
+ */
+int
+ddi_soft_state_zalloc(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void **array;
+ void *new_element;
+
+ if ((state == NULL) || (item < 0))
+ return (DDI_FAILURE);
+
+ mutex_enter(&ss->lock);
+ if (ss->size == 0) {
+ mutex_exit(&ss->lock);
+ cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
+ "fake");
+ return (DDI_FAILURE);
+ }
+
+ array = ss->array; /* NULL if ss->n_items == 0 */
+ ASSERT(ss->n_items != 0 && array != NULL);
+
+ /*
+ * refuse to tread on an existing element
+ */
+ if (item < ss->n_items && array[item] != NULL) {
+ mutex_exit(&ss->lock);
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Allocate a new element to plug in
+ */
+ new_element = kmem_zalloc(ss->size, KM_SLEEP);
+
+ /*
+ * Check if the array is big enough, if not, grow it.
+ */
+ if (item >= ss->n_items) {
+ void **new_array;
+ size_t new_n_items;
+
+ /*
+ * Allocate a new array of the right length, copy
+ * all the old pointers to the new array, then
+ * if it exists at all, put the old array on the
+ * dirty list.
+ *
+ * Note that we can't kmem_free() the old array.
+ *
+ * Why -- well the 'get' operation is 'mutex-free', so we
+ * can't easily catch a suspended thread that is just about
+ * to dereference the array we just grew out of. So we
+ * cons up a header and put it on a list of 'dirty'
+ * pointer arrays. (Dirty in the sense that there may
+ * be suspended threads somewhere that are in the middle
+ * of referencing them). Fortunately, we -can- garbage
+ * collect it all at ddi_soft_state_fini time.
+ */
+ new_n_items = ss->n_items;
+ while (new_n_items < (1 + item))
+ new_n_items <<= 1; /* double array size .. */
+
+ ASSERT(new_n_items >= (1 + item)); /* sanity check! */
+
+ new_array = kmem_zalloc(new_n_items * sizeof (void *),
+ KM_SLEEP);
+ /*
+ * Copy the pointers into the new array
+ */
+ bcopy(array, new_array, ss->n_items * sizeof (void *));
+
+ /*
+ * Free the old array now. Note that
+ * ddi_get_soft_state takes the mutex.
+ */
+ kmem_free(ss->array, ss->n_items * sizeof (void *));
+
+ ss->array = (array = new_array);
+ ss->n_items = new_n_items;
+ }
+
+ ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
+
+ array[item] = new_element;
+
+ mutex_exit(&ss->lock);
+ return (DDI_SUCCESS);
+}
+
+void
+ddi_soft_state_free(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void **array;
+ void *element;
+ static char msg[] = "ddi_soft_state_free:";
+
+ if (ss == NULL) {
+ cmn_err(CE_WARN, "%s null handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ element = NULL;
+
+ mutex_enter(&ss->lock);
+
+ if ((array = ss->array) == NULL || ss->size == 0) {
+ cmn_err(CE_WARN, "%s bad handle: %s",
+ msg, "fake");
+ } else if (item < 0 || item >= ss->n_items) {
+ cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
+ msg, item, (ulong_t)ss->n_items - 1, "fake");
+ } else if (array[item] != NULL) {
+ element = array[item];
+ array[item] = NULL;
+ }
+
+ mutex_exit(&ss->lock);
+
+ if (element)
+ kmem_free(element, ss->size);
+}
+
+/*
+ * Free the entire set of pointers, and any
+ * soft state structures contained therein.
+ *
+ * Note that we don't grab the ss->lock mutex, even though
+ * we're inspecting the various fields of the data structure.
+ *
+ * There is an implicit assumption that this routine will
+ * never run concurrently with any of the above on this
+ * particular state structure i.e. by the time the driver
+ * calls this routine, there should be no other threads
+ * running in the driver.
+ */
+void
+ddi_soft_state_fini(void **state_p)
+{
+ i_ddi_soft_state *ss;
+ int item;
+ static char msg[] = "ddi_soft_state_fini:";
+
+ if (state_p == NULL ||
+ (ss = (i_ddi_soft_state *)(*state_p)) == NULL) {
+ cmn_err(CE_WARN, "%s null handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ if (ss->size == 0) {
+ cmn_err(CE_WARN, "%s bad handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ if (ss->n_items > 0) {
+ for (item = 0; item < ss->n_items; item++)
+ ddi_soft_state_free(ss, item);
+ kmem_free(ss->array, ss->n_items * sizeof (void *));
+ }
+
+ mutex_destroy(&ss->lock);
+ kmem_free(ss, sizeof (*ss));
+
+ *state_p = NULL;
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c
new file mode 100644
index 0000000000..d89a732d69
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c
@@ -0,0 +1,1377 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/thread.h>
+#include <sys/sysmacros.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/conf.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/errno.h>
+#include <sys/vtrace.h>
+#include <sys/ftrace.h>
+#include <sys/ontrap.h>
+#include <sys/sdt.h>
+#include <sys/strft.h>
+
+/*
+ * This file contains selected functions from io/stream.c
+ * needed by this library, mostly unmodified.
+ */
+
+/*
+ * STREAMS message allocator: principles of operation
+ * (See usr/src/uts/common/io/stream.c)
+ */
+#define DBLK_MAX_CACHE 73728
+#define DBLK_CACHE_ALIGN 64
+#define DBLK_MIN_SIZE 8
+#define DBLK_SIZE_SHIFT 3
+
+#ifdef _BIG_ENDIAN
+#define DBLK_RTFU_SHIFT(field) \
+ (8 * (&((dblk_t *)0)->db_struioflag - &((dblk_t *)0)->field))
+#else
+#define DBLK_RTFU_SHIFT(field) \
+ (8 * (&((dblk_t *)0)->field - &((dblk_t *)0)->db_ref))
+#endif
+
+#define DBLK_RTFU(ref, type, flags, uioflag) \
+ (((ref) << DBLK_RTFU_SHIFT(db_ref)) | \
+ ((type) << DBLK_RTFU_SHIFT(db_type)) | \
+ (((flags) | (ref - 1)) << DBLK_RTFU_SHIFT(db_flags)) | \
+ ((uioflag) << DBLK_RTFU_SHIFT(db_struioflag)))
+#define DBLK_RTFU_REF_MASK (DBLK_REFMAX << DBLK_RTFU_SHIFT(db_ref))
+#define DBLK_RTFU_WORD(dbp) (*((uint32_t *)&(dbp)->db_ref))
+#define MBLK_BAND_FLAG_WORD(mp) (*((uint32_t *)&(mp)->b_band))
+
+static size_t dblk_sizes[] = {
+#ifdef _LP64
+ 16, 80, 144, 208, 272, 336, 528, 1040, 1488, 1936, 2576, 3856,
+ 8192, 12048, 16384, 20240, 24576, 28432, 32768, 36624,
+ 40960, 44816, 49152, 53008, 57344, 61200, 65536, 69392,
+#else
+ 64, 128, 320, 576, 1088, 1536, 1984, 2624, 3904,
+ 8192, 12096, 16384, 20288, 24576, 28480, 32768, 36672,
+ 40960, 44864, 49152, 53056, 57344, 61248, 65536, 69440,
+#endif
+ DBLK_MAX_CACHE, 0
+};
+
+static struct kmem_cache *dblk_cache[DBLK_MAX_CACHE / DBLK_MIN_SIZE];
+static struct kmem_cache *mblk_cache;
+static struct kmem_cache *dblk_esb_cache;
+
+static void dblk_lastfree(mblk_t *mp, dblk_t *dbp);
+static mblk_t *allocb_oversize(size_t size, int flags);
+static int allocb_tryhard_fails;
+static void frnop_func(void *arg);
+frtn_t frnop = { frnop_func };
+static void bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp);
+
+/*
+ * Patchable mblk/dblk kmem_cache flags.
+ */
+int dblk_kmem_flags = 0;
+int mblk_kmem_flags = 0;
+
+static int
+dblk_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+ ssize_t msg_size = (ssize_t)cdrarg;
+ size_t index;
+
+ ASSERT(msg_size != 0);
+
+ index = (msg_size - 1) >> DBLK_SIZE_SHIFT;
+
+ ASSERT(index < (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT));
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+ if ((msg_size & PAGEOFFSET) == 0) {
+ dbp->db_base = kmem_alloc(msg_size, kmflags);
+ if (dbp->db_base == NULL) {
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+ return (-1);
+ }
+ } else {
+ dbp->db_base = (unsigned char *)&dbp[1];
+ }
+
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = dblk_cache[index];
+ dbp->db_lim = dbp->db_base + msg_size;
+ dbp->db_free = dbp->db_lastfree = dblk_lastfree;
+ dbp->db_frtnp = NULL;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dblk_esb_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = dblk_esb_cache;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+static int
+bcache_dblk_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+ bcache_t *bcp = cdrarg;
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+
+ dbp->db_base = kmem_cache_alloc(bcp->buffer_cache, kmflags);
+ if (dbp->db_base == NULL) {
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+ return (-1);
+ }
+
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = (void *)bcp;
+ dbp->db_lim = dbp->db_base + bcp->size;
+ dbp->db_free = dbp->db_lastfree = bcache_dblk_lastfree;
+ dbp->db_frtnp = NULL;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+static void
+dblk_destructor(void *buf, void *cdrarg)
+{
+ dblk_t *dbp = buf;
+ ssize_t msg_size = (ssize_t)cdrarg;
+
+ ASSERT(dbp->db_mblk->b_datap == dbp);
+ ASSERT(msg_size != 0);
+ ASSERT(dbp->db_struioflag == 0);
+ ASSERT(dbp->db_struioun.cksum.flags == 0);
+
+ if ((msg_size & PAGEOFFSET) == 0) {
+ kmem_free(dbp->db_base, msg_size);
+ }
+
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+}
+
+static void
+bcache_dblk_destructor(void *buf, void *cdrarg)
+{
+ dblk_t *dbp = buf;
+ bcache_t *bcp = cdrarg;
+
+ kmem_cache_free(bcp->buffer_cache, dbp->db_base);
+
+ ASSERT(dbp->db_mblk->b_datap == dbp);
+ ASSERT(dbp->db_struioflag == 0);
+ ASSERT(dbp->db_struioun.cksum.flags == 0);
+
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+}
+
+/* Needed in the ASSERT below */
+#ifdef DEBUG
+#ifdef _KERNEL
+#define KMEM_SLAB_T_SZ sizeof (kmem_slab_t)
+#else /* _KERNEL */
+#define KMEM_SLAB_T_SZ 64 /* fakekernel */
+#endif /* _KERNEL */
+#endif /* DEBUG */
+
+void
+streams_msg_init(void)
+{
+ char name[40];
+ size_t size;
+ size_t lastsize = DBLK_MIN_SIZE;
+ size_t *sizep;
+ struct kmem_cache *cp;
+ size_t tot_size;
+ int offset;
+
+ mblk_cache = kmem_cache_create("streams_mblk", sizeof (mblk_t), 32,
+ NULL, NULL, NULL, NULL, NULL, mblk_kmem_flags);
+
+ for (sizep = dblk_sizes; (size = *sizep) != 0; sizep++) {
+
+ if ((offset = (size & PAGEOFFSET)) != 0) {
+ /*
+ * We are in the middle of a page, dblk should
+ * be allocated on the same page
+ */
+ tot_size = size + sizeof (dblk_t);
+ ASSERT((offset + sizeof (dblk_t) + KMEM_SLAB_T_SZ)
+ < PAGESIZE);
+ ASSERT((tot_size & (DBLK_CACHE_ALIGN - 1)) == 0);
+
+ } else {
+
+ /*
+ * buf size is multiple of page size, dblk and
+ * buffer are allocated separately.
+ */
+
+ ASSERT((size & (DBLK_CACHE_ALIGN - 1)) == 0);
+ tot_size = sizeof (dblk_t);
+ }
+
+ (void) sprintf(name, "streams_dblk_%ld", (long)size);
+ cp = kmem_cache_create(name, tot_size, DBLK_CACHE_ALIGN,
+ dblk_constructor, dblk_destructor, NULL, (void *)(size),
+ NULL, dblk_kmem_flags);
+
+ while (lastsize <= size) {
+ dblk_cache[(lastsize - 1) >> DBLK_SIZE_SHIFT] = cp;
+ lastsize += DBLK_MIN_SIZE;
+ }
+ }
+
+ dblk_esb_cache = kmem_cache_create("streams_dblk_esb", sizeof (dblk_t),
+ DBLK_CACHE_ALIGN, dblk_esb_constructor, dblk_destructor, NULL,
+ (void *)sizeof (dblk_t), NULL, dblk_kmem_flags);
+
+ /* fthdr_cache, ftblk_cache, mmd_init... */
+}
+
+/*ARGSUSED*/
+mblk_t *
+allocb(size_t size, uint_t pri)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+ size_t index;
+
+ index = (size - 1) >> DBLK_SIZE_SHIFT;
+
+ if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
+ if (size != 0) {
+ mp = allocb_oversize(size, KM_NOSLEEP);
+ goto out;
+ }
+ index = 0;
+ }
+
+ if ((dbp = kmem_cache_alloc(dblk_cache[index], KM_NOSLEEP)) == NULL) {
+ mp = NULL;
+ goto out;
+ }
+
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&dbp->db_fthdr, FTEV_ALLOCB, size);
+out:
+ FTRACE_1("allocb(): mp=0x%p", (uintptr_t)mp);
+
+ return (mp);
+}
+
+/*
+ * Allocate an mblk taking db_credp and db_cpid from the template.
+ * Allow the cred to be NULL.
+ */
+mblk_t *
+allocb_tmpl(size_t size, const mblk_t *tmpl)
+{
+ mblk_t *mp = allocb(size, 0);
+
+ if (mp != NULL) {
+ dblk_t *src = tmpl->b_datap;
+ dblk_t *dst = mp->b_datap;
+ cred_t *cr;
+ pid_t cpid;
+
+ cr = msg_getcred(tmpl, &cpid);
+ if (cr != NULL)
+ crhold(dst->db_credp = cr);
+ dst->db_cpid = cpid;
+ dst->db_type = src->db_type;
+ }
+ return (mp);
+}
+
+mblk_t *
+allocb_cred(size_t size, cred_t *cr, pid_t cpid)
+{
+ mblk_t *mp = allocb(size, 0);
+
+ ASSERT(cr != NULL);
+ if (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ crhold(dbp->db_credp = cr);
+ dbp->db_cpid = cpid;
+ }
+ return (mp);
+}
+
+mblk_t *
+allocb_cred_wait(size_t size, uint_t flags, int *error, cred_t *cr, pid_t cpid)
+{
+ mblk_t *mp = allocb_wait(size, 0, flags, error);
+
+ ASSERT(cr != NULL);
+ if (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ crhold(dbp->db_credp = cr);
+ dbp->db_cpid = cpid;
+ }
+
+ return (mp);
+}
+
+/*
+ * Extract the db_cred (and optionally db_cpid) from a message.
+ * We find the first mblk which has a non-NULL db_cred and use that.
+ * If none found we return NULL.
+ * Does NOT get a hold on the cred.
+ */
+cred_t *
+msg_getcred(const mblk_t *mp, pid_t *cpidp)
+{
+ cred_t *cr = NULL;
+
+ while (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ cr = dbp->db_credp;
+ if (cr == NULL) {
+ mp = mp->b_cont;
+ continue;
+ }
+ if (cpidp != NULL)
+ *cpidp = dbp->db_cpid;
+
+ /* DEBUG check for only one db_credp */
+ return (cr);
+ }
+ if (cpidp != NULL)
+ *cpidp = NOPID;
+ return (NULL);
+}
+
+/*
+ * Variant of msg_getcred which, when a cred is found
+ * 1. Returns with a hold on the cred
+ * 2. Clears the first cred in the mblk.
+ * This is more efficient to use than a msg_getcred() + crhold() when
+ * the message is freed after the cred has been extracted.
+ *
+ * The caller is responsible for ensuring that there is no other reference
+ * on the message since db_credp can not be cleared when there are other
+ * references.
+ */
+cred_t *
+msg_extractcred(mblk_t *mp, pid_t *cpidp)
+{
+ cred_t *cr = NULL;
+
+ while (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ cr = dbp->db_credp;
+ if (cr == NULL) {
+ mp = mp->b_cont;
+ continue;
+ }
+ ASSERT(dbp->db_ref == 1);
+ dbp->db_credp = NULL;
+ if (cpidp != NULL)
+ *cpidp = dbp->db_cpid;
+
+ /* DEBUG check for only one db_credp */
+ return (cr);
+ }
+ return (NULL);
+}
+
+/* _KERNEL msg_getlabel() */
+
+void
+freeb(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+
+ ASSERT(dbp->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+ FTRACE_1("freeb(): mp=0x%lx", (uintptr_t)mp);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
+
+ dbp->db_free(mp, dbp);
+}
+
+void
+freemsg(mblk_t *mp)
+{
+ FTRACE_1("freemsg(): mp=0x%lx", (uintptr_t)mp);
+ while (mp) {
+ dblk_t *dbp = mp->b_datap;
+ mblk_t *mp_cont = mp->b_cont;
+
+ ASSERT(dbp->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
+
+ dbp->db_free(mp, dbp);
+ mp = mp_cont;
+ }
+}
+
+/*
+ * Reallocate a block for another use. Try hard to use the old block.
+ * If the old data is wanted (copy), leave b_wptr at the end of the data,
+ * otherwise return b_wptr = b_rptr.
+ *
+ * This routine is private and unstable.
+ */
+mblk_t *
+reallocb(mblk_t *mp, size_t size, uint_t copy)
+{
+ mblk_t *mp1;
+ unsigned char *old_rptr;
+ ptrdiff_t cur_size;
+
+ if (mp == NULL)
+ return (allocb(size, BPRI_HI));
+
+ cur_size = mp->b_wptr - mp->b_rptr;
+ old_rptr = mp->b_rptr;
+
+ ASSERT(mp->b_datap->db_ref != 0);
+
+ if (mp->b_datap->db_ref == 1 && MBLKSIZE(mp) >= size) {
+ /*
+ * If the data is wanted and it will fit where it is, no
+ * work is required.
+ */
+ if (copy && mp->b_datap->db_lim - mp->b_rptr >= size)
+ return (mp);
+
+ mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
+ mp1 = mp;
+ } else if ((mp1 = allocb_tmpl(size, mp)) != NULL) {
+ /* XXX other mp state could be copied too, db_flags ... ? */
+ mp1->b_cont = mp->b_cont;
+ } else {
+ return (NULL);
+ }
+
+ if (copy) {
+ bcopy(old_rptr, mp1->b_rptr, cur_size);
+ mp1->b_wptr = mp1->b_rptr + cur_size;
+ }
+
+ if (mp != mp1)
+ freeb(mp);
+
+ return (mp1);
+}
+
+static void
+dblk_lastfree(mblk_t *mp, dblk_t *dbp)
+{
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+
+ /* Reset the struioflag and the checksum flag fields */
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ /* and the COOKED and/or UIOA flag(s) */
+ dbp->db_flags &= ~(DBLK_COOKED | DBLK_UIOA);
+
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+static void
+dblk_decref(mblk_t *mp, dblk_t *dbp)
+{
+ if (dbp->db_ref != 1) {
+ uint32_t rtfu = atomic_add_32_nv(&DBLK_RTFU_WORD(dbp),
+ -(1 << DBLK_RTFU_SHIFT(db_ref)));
+ /*
+ * atomic_add_32_nv() just decremented db_ref, so we no longer
+ * have a reference to the dblk, which means another thread
+ * could free it. Therefore we cannot examine the dblk to
+ * determine whether ours was the last reference. Instead,
+ * we extract the new and minimum reference counts from rtfu.
+ * Note that all we're really saying is "if (ref != refmin)".
+ */
+ if (((rtfu >> DBLK_RTFU_SHIFT(db_ref)) & DBLK_REFMAX) !=
+ ((rtfu >> DBLK_RTFU_SHIFT(db_flags)) & DBLK_REFMIN)) {
+ kmem_cache_free(mblk_cache, mp);
+ return;
+ }
+ }
+ dbp->db_mblk = mp;
+ dbp->db_free = dbp->db_lastfree;
+ dbp->db_lastfree(mp, dbp);
+}
+
+mblk_t *
+dupb(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+ mblk_t *new_mp;
+ uint32_t oldrtfu, newrtfu;
+
+ if ((new_mp = kmem_cache_alloc(mblk_cache, KM_NOSLEEP)) == NULL)
+ goto out;
+
+ new_mp->b_next = new_mp->b_prev = new_mp->b_cont = NULL;
+ new_mp->b_rptr = mp->b_rptr;
+ new_mp->b_wptr = mp->b_wptr;
+ new_mp->b_datap = dbp;
+ new_mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(new_mp) = MBLK_BAND_FLAG_WORD(mp);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_DUPB, dbp->db_ref);
+
+ dbp->db_free = dblk_decref;
+ do {
+ ASSERT(dbp->db_ref > 0);
+ oldrtfu = DBLK_RTFU_WORD(dbp);
+ newrtfu = oldrtfu + (1 << DBLK_RTFU_SHIFT(db_ref));
+ /*
+ * If db_ref is maxed out we can't dup this message anymore.
+ */
+ if ((oldrtfu & DBLK_RTFU_REF_MASK) == DBLK_RTFU_REF_MASK) {
+ kmem_cache_free(mblk_cache, new_mp);
+ new_mp = NULL;
+ goto out;
+ }
+ } while (atomic_cas_32(&DBLK_RTFU_WORD(dbp), oldrtfu, newrtfu) !=
+ oldrtfu);
+
+out:
+ FTRACE_1("dupb(): new_mp=0x%lx", (uintptr_t)new_mp);
+ return (new_mp);
+}
+
+/*ARGSUSED*/
+static void
+frnop_func(void *arg)
+{
+}
+
+/*
+ * Generic esballoc used to implement the four flavors: [d]esballoc[a].
+ * and allocb_oversize
+ */
+static mblk_t *
+gesballoc(unsigned char *base, size_t size, uint32_t db_rtfu, frtn_t *frp,
+ void (*lastfree)(mblk_t *, dblk_t *), int kmflags)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+
+ ASSERT(base != NULL && frp != NULL);
+
+ if ((dbp = kmem_cache_alloc(dblk_esb_cache, kmflags)) == NULL) {
+ mp = NULL;
+ goto out;
+ }
+
+ mp = dbp->db_mblk;
+ dbp->db_base = base;
+ dbp->db_lim = base + size;
+ dbp->db_free = dbp->db_lastfree = lastfree;
+ dbp->db_frtnp = frp;
+ DBLK_RTFU_WORD(dbp) = db_rtfu;
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+
+out:
+ FTRACE_1("gesballoc(): mp=0x%lx", (uintptr_t)mp);
+ return (mp);
+}
+
+static void
+bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp)
+{
+ bcache_t *bcp = dbp->db_cache;
+
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ mutex_enter(&bcp->mutex);
+ kmem_cache_free(bcp->dblk_cache, dbp);
+ bcp->alloc--;
+
+ if (bcp->alloc == 0 && bcp->destroy != 0) {
+ kmem_cache_destroy(bcp->dblk_cache);
+ kmem_cache_destroy(bcp->buffer_cache);
+ mutex_exit(&bcp->mutex);
+ mutex_destroy(&bcp->mutex);
+ kmem_free(bcp, sizeof (bcache_t));
+ } else {
+ mutex_exit(&bcp->mutex);
+ }
+}
+
+bcache_t *
+bcache_create(char *name, size_t size, uint_t align)
+{
+ bcache_t *bcp;
+ char buffer[255];
+
+ ASSERT((align & (align - 1)) == 0);
+
+ if ((bcp = kmem_alloc(sizeof (bcache_t), KM_NOSLEEP)) == NULL)
+ return (NULL);
+
+ bcp->size = size;
+ bcp->align = align;
+ bcp->alloc = 0;
+ bcp->destroy = 0;
+
+ mutex_init(&bcp->mutex, NULL, MUTEX_DRIVER, NULL);
+
+ (void) sprintf(buffer, "%s_buffer_cache", name);
+ bcp->buffer_cache = kmem_cache_create(buffer, size, align, NULL, NULL,
+ NULL, NULL, NULL, 0);
+ (void) sprintf(buffer, "%s_dblk_cache", name);
+ bcp->dblk_cache = kmem_cache_create(buffer, sizeof (dblk_t),
+ DBLK_CACHE_ALIGN, bcache_dblk_constructor, bcache_dblk_destructor,
+ NULL, (void *)bcp, NULL, 0);
+
+ return (bcp);
+}
+
+void
+bcache_destroy(bcache_t *bcp)
+{
+ ASSERT(bcp != NULL);
+
+ mutex_enter(&bcp->mutex);
+ if (bcp->alloc == 0) {
+ kmem_cache_destroy(bcp->dblk_cache);
+ kmem_cache_destroy(bcp->buffer_cache);
+ mutex_exit(&bcp->mutex);
+ mutex_destroy(&bcp->mutex);
+ kmem_free(bcp, sizeof (bcache_t));
+ } else {
+ bcp->destroy++;
+ mutex_exit(&bcp->mutex);
+ }
+}
+
+/*ARGSUSED*/
+mblk_t *
+bcache_allocb(bcache_t *bcp, uint_t pri)
+{
+ dblk_t *dbp;
+ mblk_t *mp = NULL;
+
+ ASSERT(bcp != NULL);
+
+ mutex_enter(&bcp->mutex);
+ if (bcp->destroy != 0) {
+ mutex_exit(&bcp->mutex);
+ goto out;
+ }
+
+ if ((dbp = kmem_cache_alloc(bcp->dblk_cache, KM_NOSLEEP)) == NULL) {
+ mutex_exit(&bcp->mutex);
+ goto out;
+ }
+ bcp->alloc++;
+ mutex_exit(&bcp->mutex);
+
+ ASSERT(((uintptr_t)(dbp->db_base) & (bcp->align - 1)) == 0);
+
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&dbp->db_fthdr, FTEV_BCALLOCB, bcp->size);
+out:
+ FTRACE_1("bcache_allocb(): mp=0x%p", (uintptr_t)mp);
+
+ return (mp);
+}
+
+static void
+dblk_lastfree_oversize(mblk_t *mp, dblk_t *dbp)
+{
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ kmem_free(dbp->db_base, dbp->db_lim - dbp->db_base);
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+static mblk_t *
+allocb_oversize(size_t size, int kmflags)
+{
+ mblk_t *mp;
+ void *buf;
+
+ size = P2ROUNDUP(size, DBLK_CACHE_ALIGN);
+ if ((buf = kmem_alloc(size, kmflags)) == NULL)
+ return (NULL);
+ if ((mp = gesballoc(buf, size, DBLK_RTFU(1, M_DATA, 0, 0),
+ &frnop, dblk_lastfree_oversize, kmflags)) == NULL)
+ kmem_free(buf, size);
+
+ if (mp != NULL)
+ STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBIG, size);
+
+ return (mp);
+}
+
+mblk_t *
+allocb_tryhard(size_t target_size)
+{
+ size_t size;
+ mblk_t *bp;
+
+ for (size = target_size; size < target_size + 512;
+ size += DBLK_CACHE_ALIGN)
+ if ((bp = allocb(size, BPRI_HI)) != NULL)
+ return (bp);
+ allocb_tryhard_fails++;
+ return (NULL);
+}
+
+/*
+ * This routine is consolidation private for STREAMS internal use
+ * This routine may only be called from sync routines (i.e., not
+ * from put or service procedures). It is located here (rather
+ * than strsubr.c) so that we don't have to expose all of the
+ * allocb() implementation details in header files.
+ */
+mblk_t *
+allocb_wait(size_t size, uint_t pri, uint_t flags, int *error)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+ size_t index;
+
+ index = (size -1) >> DBLK_SIZE_SHIFT;
+
+ if (flags & STR_NOSIG) {
+ if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
+ if (size != 0) {
+ mp = allocb_oversize(size, KM_SLEEP);
+ FTRACE_1("allocb_wait (NOSIG): mp=0x%lx",
+ (uintptr_t)mp);
+ return (mp);
+ }
+ index = 0;
+ }
+
+ dbp = kmem_cache_alloc(dblk_cache[index], KM_SLEEP);
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBW, size);
+
+ FTRACE_1("allocb_wait (NOSIG): mp=0x%lx", (uintptr_t)mp);
+
+ } else {
+ while ((mp = allocb(size, pri)) == NULL) {
+ if ((*error = strwaitbuf(size, BPRI_HI)) != 0)
+ return (NULL);
+ }
+ }
+
+ return (mp);
+}
+
+/*
+ * Call function 'func' with 'arg' when a class zero block can
+ * be allocated with priority 'pri'.
+ */
+bufcall_id_t
+esbbcall(uint_t pri, void (*func)(void *), void *arg)
+{
+ return (bufcall(1, pri, func, arg));
+}
+
+/*
+ * Allocates an iocblk (M_IOCTL) block. Properly sets the credentials
+ * ioc_id, rval and error of the struct ioctl to set up an ioctl call.
+ * This provides consistency for all internal allocators of ioctl.
+ */
+mblk_t *
+mkiocb(uint_t cmd)
+{
+ struct iocblk *ioc;
+ mblk_t *mp;
+
+ /*
+ * Allocate enough space for any of the ioctl related messages.
+ */
+ if ((mp = allocb(sizeof (union ioctypes), BPRI_MED)) == NULL)
+ return (NULL);
+
+ bzero(mp->b_rptr, sizeof (union ioctypes));
+
+ /*
+ * Set the mblk_t information and ptrs correctly.
+ */
+ mp->b_wptr += sizeof (struct iocblk);
+ mp->b_datap->db_type = M_IOCTL;
+
+ /*
+ * Fill in the fields.
+ */
+ ioc = (struct iocblk *)mp->b_rptr;
+ ioc->ioc_cmd = cmd;
+ ioc->ioc_cr = kcred;
+ ioc->ioc_id = getiocseqno();
+ ioc->ioc_flag = IOC_NATIVE;
+ return (mp);
+}
+
+/*
+ * test if block of given size can be allocated with a request of
+ * the given priority.
+ * 'pri' is no longer used, but is retained for compatibility.
+ */
+/* ARGSUSED */
+int
+testb(size_t size, uint_t pri)
+{
+ return ((size + sizeof (dblk_t)) <= kmem_avail());
+}
+
+/* _KERNEL: bufcall, unbufcall */
+
+/*
+ * Duplicate a message block by block (uses dupb), returning
+ * a pointer to the duplicate message.
+ * Returns a non-NULL value only if the entire message
+ * was dup'd.
+ */
+mblk_t *
+dupmsg(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (!bp || !(nbp = head = dupb(bp)))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if (!(nbp->b_cont = dupb(bp->b_cont))) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+#define DUPB_NOLOAN(bp) \
+ ((((bp)->b_datap->db_struioflag & STRUIO_ZC) != 0) ? \
+ copyb((bp)) : dupb((bp)))
+
+mblk_t *
+dupmsg_noloan(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (bp == NULL || DB_TYPE(bp) != M_DATA ||
+ ((nbp = head = DUPB_NOLOAN(bp)) == NULL))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if ((nbp->b_cont = DUPB_NOLOAN(bp->b_cont)) == NULL) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+/*
+ * Copy data from message and data block to newly allocated message and
+ * data block. Returns new message block pointer, or NULL if error.
+ * The alignment of rptr (w.r.t. word alignment) will be the same in the copy
+ * as in the original even when db_base is not word aligned. (bug 1052877)
+ */
+mblk_t *
+copyb(mblk_t *bp)
+{
+ mblk_t *nbp;
+ dblk_t *dp, *ndp;
+ uchar_t *base;
+ size_t size;
+ size_t unaligned;
+
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+
+ dp = bp->b_datap;
+ if (dp->db_fthdr != NULL)
+ STR_FTEVENT_MBLK(bp, caller(), FTEV_COPYB, 0);
+
+ /*
+ * Special handling for Multidata message; this should be
+ * removed once a copy-callback routine is made available.
+ */
+ if (dp->db_type == M_MULTIDATA) {
+ /* _KERNEL mmd_copy stuff */
+ return (NULL);
+ }
+
+ size = dp->db_lim - dp->db_base;
+ unaligned = P2PHASE((uintptr_t)dp->db_base, sizeof (uint_t));
+ if ((nbp = allocb_tmpl(size + unaligned, bp)) == NULL)
+ return (NULL);
+ nbp->b_flag = bp->b_flag;
+ nbp->b_band = bp->b_band;
+ ndp = nbp->b_datap;
+
+ /*
+ * Well, here is a potential issue. If we are trying to
+ * trace a flow, and we copy the message, we might lose
+ * information about where this message might have been.
+ * So we should inherit the FT data. On the other hand,
+ * a user might be interested only in alloc to free data.
+ * So I guess the real answer is to provide a tunable.
+ */
+ STR_FTEVENT_MBLK(nbp, caller(), FTEV_COPYB, 1);
+
+ base = ndp->db_base + unaligned;
+ bcopy(dp->db_base, ndp->db_base + unaligned, size);
+
+ nbp->b_rptr = base + (bp->b_rptr - dp->db_base);
+ nbp->b_wptr = nbp->b_rptr + MBLKL(bp);
+
+ return (nbp);
+}
+
+/*
+ * Copy data from message to newly allocated message using new
+ * data blocks. Returns a pointer to the new message, or NULL if error.
+ */
+mblk_t *
+copymsg(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (!bp || !(nbp = head = copyb(bp)))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if (!(nbp->b_cont = copyb(bp->b_cont))) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+/*
+ * link a message block to tail of message
+ */
+void
+linkb(mblk_t *mp, mblk_t *bp)
+{
+ ASSERT(mp && bp);
+
+ for (; mp->b_cont; mp = mp->b_cont)
+ ;
+ mp->b_cont = bp;
+}
+
+/*
+ * unlink a message block from head of message
+ * return pointer to new message.
+ * NULL if message becomes empty.
+ */
+mblk_t *
+unlinkb(mblk_t *bp)
+{
+ mblk_t *bp1;
+
+ bp1 = bp->b_cont;
+ bp->b_cont = NULL;
+ return (bp1);
+}
+
+/*
+ * remove a message block "bp" from message "mp"
+ *
+ * Return pointer to new message or NULL if no message remains.
+ * Return -1 if bp is not found in message.
+ */
+mblk_t *
+rmvb(mblk_t *mp, mblk_t *bp)
+{
+ mblk_t *tmp;
+ mblk_t *lastp = NULL;
+
+ ASSERT(mp && bp);
+ for (tmp = mp; tmp; tmp = tmp->b_cont) {
+ if (tmp == bp) {
+ if (lastp)
+ lastp->b_cont = tmp->b_cont;
+ else
+ mp = tmp->b_cont;
+ tmp->b_cont = NULL;
+ return (mp);
+ }
+ lastp = tmp;
+ }
+ return ((mblk_t *)-1);
+}
+
+/*
+ * Concatenate and align first len bytes of common
+ * message type. Len == -1, means concat everything.
+ * Returns 1 on success, 0 on failure
+ * After the pullup, mp points to the pulled up data.
+ */
+int
+pullupmsg(mblk_t *mp, ssize_t len)
+{
+ mblk_t *bp, *b_cont;
+ dblk_t *dbp;
+ ssize_t n;
+
+ ASSERT(mp->b_datap->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (0);
+
+ if (len == -1) {
+ if (mp->b_cont == NULL && str_aligned(mp->b_rptr))
+ return (1);
+ len = xmsgsize(mp);
+ } else {
+ ssize_t first_mblk_len = mp->b_wptr - mp->b_rptr;
+ ASSERT(first_mblk_len >= 0);
+ /*
+ * If the length is less than that of the first mblk,
+ * we want to pull up the message into an aligned mblk.
+ * Though not part of the spec, some callers assume it.
+ */
+ if (len <= first_mblk_len) {
+ if (str_aligned(mp->b_rptr))
+ return (1);
+ len = first_mblk_len;
+ } else if (xmsgsize(mp) < len)
+ return (0);
+ }
+
+ if ((bp = allocb_tmpl(len, mp)) == NULL)
+ return (0);
+
+ dbp = bp->b_datap;
+ *bp = *mp; /* swap mblks so bp heads the old msg... */
+ mp->b_datap = dbp; /* ... and mp heads the new message */
+ mp->b_datap->db_mblk = mp;
+ bp->b_datap->db_mblk = bp;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+
+ do {
+ ASSERT(bp->b_datap->db_ref > 0);
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ n = MIN(bp->b_wptr - bp->b_rptr, len);
+ ASSERT(n >= 0); /* allow zero-length mblk_t's */
+ if (n > 0)
+ bcopy(bp->b_rptr, mp->b_wptr, (size_t)n);
+ mp->b_wptr += n;
+ bp->b_rptr += n;
+ len -= n;
+ if (bp->b_rptr != bp->b_wptr)
+ break;
+ b_cont = bp->b_cont;
+ freeb(bp);
+ bp = b_cont;
+ } while (len && bp);
+
+ mp->b_cont = bp; /* tack on whatever wasn't pulled up */
+
+ return (1);
+}
+
+/*
+ * Concatenate and align at least the first len bytes of common message
+ * type. Len == -1 means concatenate everything. The original message is
+ * unaltered. Returns a pointer to a new message on success, otherwise
+ * returns NULL.
+ */
+mblk_t *
+msgpullup(mblk_t *mp, ssize_t len)
+{
+ mblk_t *newmp;
+ ssize_t totlen;
+ ssize_t n;
+
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (NULL);
+
+ totlen = xmsgsize(mp);
+
+ if ((len > 0) && (len > totlen))
+ return (NULL);
+
+ /*
+ * Copy all of the first msg type into one new mblk, then dupmsg
+ * and link the rest onto this.
+ */
+
+ len = totlen;
+
+ if ((newmp = allocb_tmpl(len, mp)) == NULL)
+ return (NULL);
+
+ newmp->b_flag = mp->b_flag;
+ newmp->b_band = mp->b_band;
+
+ while (len > 0) {
+ n = mp->b_wptr - mp->b_rptr;
+ ASSERT(n >= 0); /* allow zero-length mblk_t's */
+ if (n > 0)
+ bcopy(mp->b_rptr, newmp->b_wptr, n);
+ newmp->b_wptr += n;
+ len -= n;
+ mp = mp->b_cont;
+ }
+
+ if (mp != NULL) {
+ newmp->b_cont = dupmsg(mp);
+ if (newmp->b_cont == NULL) {
+ freemsg(newmp);
+ return (NULL);
+ }
+ }
+
+ return (newmp);
+}
+
+/*
+ * Trim bytes from message
+ * len > 0, trim from head
+ * len < 0, trim from tail
+ * Returns 1 on success, 0 on failure.
+ */
+int
+adjmsg(mblk_t *mp, ssize_t len)
+{
+ mblk_t *bp;
+ mblk_t *save_bp = NULL;
+ mblk_t *prev_bp;
+ mblk_t *bcont;
+ unsigned char type;
+ ssize_t n;
+ int fromhead;
+ int first;
+
+ ASSERT(mp != NULL);
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (0);
+
+ if (len < 0) {
+ fromhead = 0;
+ len = -len;
+ } else {
+ fromhead = 1;
+ }
+
+ if (xmsgsize(mp) < len)
+ return (0);
+
+ if (fromhead) {
+ first = 1;
+ while (len) {
+ ASSERT(mp->b_wptr >= mp->b_rptr);
+ n = MIN(mp->b_wptr - mp->b_rptr, len);
+ mp->b_rptr += n;
+ len -= n;
+
+ /*
+ * If this is not the first zero length
+ * message remove it
+ */
+ if (!first && (mp->b_wptr == mp->b_rptr)) {
+ bcont = mp->b_cont;
+ freeb(mp);
+ mp = save_bp->b_cont = bcont;
+ } else {
+ save_bp = mp;
+ mp = mp->b_cont;
+ }
+ first = 0;
+ }
+ } else {
+ type = mp->b_datap->db_type;
+ while (len) {
+ bp = mp;
+ save_bp = NULL;
+
+ /*
+ * Find the last message of same type
+ */
+ while (bp && bp->b_datap->db_type == type) {
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ prev_bp = save_bp;
+ save_bp = bp;
+ bp = bp->b_cont;
+ }
+ if (save_bp == NULL)
+ break;
+ n = MIN(save_bp->b_wptr - save_bp->b_rptr, len);
+ save_bp->b_wptr -= n;
+ len -= n;
+
+ /*
+ * If this is not the first message
+ * and we have taken away everything
+ * from this message, remove it
+ */
+
+ if ((save_bp != mp) &&
+ (save_bp->b_wptr == save_bp->b_rptr)) {
+ bcont = save_bp->b_cont;
+ freeb(save_bp);
+ prev_bp->b_cont = bcont;
+ }
+ }
+ }
+ return (1);
+}
+
+/*
+ * get number of data bytes in message
+ */
+size_t
+msgdsize(mblk_t *bp)
+{
+ size_t count = 0;
+
+ for (; bp; bp = bp->b_cont)
+ if (bp->b_datap->db_type == M_DATA) {
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ count += bp->b_wptr - bp->b_rptr;
+ }
+ return (count);
+}
+
+/* getq() etc to EOF removed */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c
new file mode 100644
index 0000000000..e49313c37c
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c
@@ -0,0 +1,160 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <sys/atomic.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/cmn_err.h>
+
+#include <sys/strft.h>
+
+int str_ftnever = 0;
+
+static void mblk_free(mblk_t *);
+static void esballoc_mblk_free(mblk_t *);
+
+/*
+ * A few things from os/strsubr.c
+ */
+
+int
+strwaitbuf(size_t size, int pri)
+{
+ return (0);
+}
+
+/*
+ * Return size of message of block type (bp->b_datap->db_type)
+ */
+size_t
+xmsgsize(mblk_t *bp)
+{
+ unsigned char type;
+ size_t count = 0;
+
+ type = bp->b_datap->db_type;
+
+ for (; bp; bp = bp->b_cont) {
+ if (type != bp->b_datap->db_type)
+ break;
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ count += bp->b_wptr - bp->b_rptr;
+ }
+ return (count);
+}
+
+/* ARGSUSED */
+bufcall_id_t
+bufcall(size_t size, uint_t pri, void (*func)(void *), void *arg)
+{
+ cmn_err(CE_NOTE, "bufcall() called!");
+ return ("fake bufcall id");
+}
+
+/* ARGSUSED */
+void
+unbufcall(bufcall_id_t id)
+{
+}
+
+/* ARGSUSED */
+void
+freebs_enqueue(mblk_t *mp, dblk_t *dbp)
+{
+ /*
+ * Won't bother with esb_queue_t async free here.
+ * Rather just free this mblk directly.
+ */
+ esballoc_mblk_free(mp);
+}
+
+static void
+esballoc_mblk_free(mblk_t *mp)
+{
+ mblk_t *nextmp;
+
+ for (; mp != NULL; mp = nextmp) {
+ nextmp = mp->b_next;
+ mp->b_next = NULL;
+ mblk_free(mp);
+ }
+}
+
+static void
+mblk_free(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+ frtn_t *frp = dbp->db_frtnp;
+
+ mp->b_next = NULL;
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ ASSERT(dbp->db_fthdr == NULL);
+ frp->free_func(frp->free_arg);
+ ASSERT(dbp->db_mblk == mp);
+
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+/* ARGSUSED */
+mblk_t *
+mmd_copy(mblk_t *bp, int flags)
+{
+ return (NULL);
+}
+
+/*
+ * A little bit from os/streamio.c
+ */
+
+static volatile uint32_t ioc_id;
+
+int
+getiocseqno(void)
+{
+ uint32_t i;
+
+ i = atomic_inc_32_nv(&ioc_id);
+
+ return ((int)i);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h b/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h
new file mode 100644
index 0000000000..d58b5454c4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h
@@ -0,0 +1,314 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
+/* Copyright (c) 1996 Sun Microsystems, Inc. */
+/* All Rights Reserved */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _XTI_H
+#define _XTI_H
+
+#include <sys/types.h>
+
+/*
+ * The following include file has declarations needed by both the kernel
+ * level transport providers and the user level library. This file includes
+ * it to expose its namespaces to XTI user level interface.
+ */
+#include <sys/tpicommon.h>
+
+/*
+ * Include XTI interface level options management declarations
+ */
+#include <sys/xti_xtiopt.h>
+
+#if !defined(_XPG5)
+
+/*
+ * Include declarations related to OSI transport and management data
+ * structures, and the Internet Protocol Suite.
+ * Note: The older Unix95/XNS4 XTI spec required these to be
+ * exposed through the generic interface header.
+ */
+#include <sys/xti_osi.h>
+#include <sys/xti_inet.h>
+
+#endif /* !defined(_XPG5) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The following t_errno error codes are included in the namespace by
+ * inclusion of <sys/tpicommon.h> above. The english language error strings
+ * associated with the error values are reproduced here for easy reference.
+ *
+ * Error Value Error message string
+ * ---- ----- --------------------
+ * TBADADDR 1 Incorrect address format
+ * TBADOPT 2 Incorrect options format
+ * TACCES 3 Illegal permissions
+ * TBADF 4 Illegal file descriptor
+ * TNOADDR 5 Couldn't allocate address
+ * TOUTSTATE 6 Routine will place interface out of state
+ * TBADSEQ 7 Illegal called/calling sequence number
+ * TSYSERR 8 System error
+ * TLOOK 9 An event requires attention
+ * TBADDATA 10 Illegal amount of data
+ * TBUFOVFLW 11 Buffer not large enough
+ * TFLOW 12 Can't send message - (blocked)
+ * TNODATA 13 No message currently available
+ * TNODIS 14 Disconnect message not found
+ * TNOUDERR 15 Unitdata error message not found
+ * TBADFLAG 16 Incorrect flags specified
+ * TNOREL 17 Orderly release message not found
+ * TNOTSUPPORT 18 Primitive not supported by provider
+ * TSTATECHNG 19 State is in process of changing
+ * TNOSTRUCTYPE 20 Unsupported structure type requested
+ * TBADNAME 21 Invalid transport provider name
+ * TBADQLEN 22 Listener queue length limit is zero
+ * TADDRBUSY 23 Transport address is in use
+ * TINDOUT 24 Outstanding connection indications
+ * TPROVMISMATCH 25 Listener-acceptor transport provider mismatch
+ * TRESQLEN 26 Connection acceptor has listen queue length
+ * limit greater than zero
+ * TRESADDR 27 Connection acceptor-listener addresses not
+ * same but required by transport
+ * TQFULL 28 Incoming connection queue is full
+ * TPROTO 29 Protocol error on transport primitive
+ *
+ */
+
+/*
+ * The following are the events returned by t_look
+ */
+#define T_LISTEN 0x0001 /* connection indication received */
+#define T_CONNECT 0x0002 /* connect confirmation received */
+#define T_DATA 0x0004 /* normal data received */
+#define T_EXDATA 0x0008 /* expedited data received */
+#define T_DISCONNECT 0x0010 /* disconnect received */
+#define T_UDERR 0x0040 /* data gram error indication */
+#define T_ORDREL 0x0080 /* orderly release indication */
+#define T_GODATA 0x0100 /* sending normal data is again possible */
+#define T_GOEXDATA 0x0200 /* sending expedited data is again possible */
+
+/*
+ * Flags for data primitives
+ */
+#define T_MORE 0x001 /* more data */
+#define T_EXPEDITED 0x002 /* expedited data */
+#define T_PUSH 0x004 /* send data immediately */
+
+/*
+ * XTI error return
+ */
+#if defined(_REENTRANT) || defined(_TS_ERRNO)
+extern int *__t_errno();
+#define t_errno (*(__t_errno()))
+#else
+#error "extern int t_errno?"
+#endif /* defined(_REENTRANT) || defined(_TS_ERRNO) */
+
+
+/*
+ * The following are for t_sysconf()
+ */
+#ifndef T_IOV_MAX
+#define T_IOV_MAX 16 /* Maximum number of scatter/gather buffers */
+#endif /* Should be <= IOV_MAX */
+
+#ifndef _SC_T_IOV_MAX
+#define _SC_T_IOV_MAX 79 /* Should be same in <unistd.h> for use by */
+#endif /* sysconf() */
+
+struct t_iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+/*
+ * Translate source level interface to binary entry point names.
+ *
+ * Note: This is done to maintain co-existence of TLI and XTI
+ * interfaces which have identical names for most functions but
+ * different semantics. The XTI names are moved to the different
+ * prefix space in the ABI. The #ifdef is required to make use of
+ * of the compiler feature to allow redefinition of external names
+ * where available. Otherwise a simple #define is used when this
+ * header is used with other compilers.
+ * The use of #define also has the effect of renaming all names (not
+ * just function names) to the new name. The TLI function names
+ * (e.g. t_bind) can have identical names for structure names
+ * (e.g struct t_bind). Therefore, this redefinition of names needs
+ * to be before all structure and function name declarations in the header.
+ */
+
+#ifdef __PRAGMA_REDEFINE_EXTNAME
+
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#pragma redefine_extname t_accept _xti_accept
+#else
+#pragma redefine_extname t_accept _xti_xns5_accept
+#endif
+#pragma redefine_extname t_alloc _xti_alloc
+#pragma redefine_extname t_bind _xti_bind
+#pragma redefine_extname t_close _xti_close
+#pragma redefine_extname t_connect _xti_connect
+#pragma redefine_extname t_error _xti_error
+#pragma redefine_extname t_free _xti_free
+#pragma redefine_extname t_getinfo _xti_getinfo
+#pragma redefine_extname t_getstate _xti_getstate
+#pragma redefine_extname t_getprotaddr _xti_getprotaddr
+#pragma redefine_extname t_listen _xti_listen
+#pragma redefine_extname t_look _xti_look
+#pragma redefine_extname t_open _xti_open
+#pragma redefine_extname t_optmgmt _xti_optmgmt
+#pragma redefine_extname t_rcv _xti_rcv
+#pragma redefine_extname t_rcvconnect _xti_rcvconnect
+#pragma redefine_extname t_rcvdis _xti_rcvdis
+#pragma redefine_extname t_rcvrel _xti_rcvrel
+#pragma redefine_extname t_rcvreldata _xti_rcvreldata
+#pragma redefine_extname t_rcvudata _xti_rcvudata
+#pragma redefine_extname t_rcvuderr _xti_rcvuderr
+#pragma redefine_extname t_rcvv _xti_rcvv
+#pragma redefine_extname t_rcvvudata _xti_rcvvudata
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#pragma redefine_extname t_snd _xti_snd
+#else
+#pragma redefine_extname t_snd _xti_xns5_snd
+#endif
+#pragma redefine_extname t_snddis _xti_snddis
+#pragma redefine_extname t_sndrel _xti_sndrel
+#pragma redefine_extname t_sndreldata _xti_sndreldata
+#pragma redefine_extname t_sndudata _xti_sndudata
+#pragma redefine_extname t_sndv _xti_sndv
+#pragma redefine_extname t_sndvudata _xti_sndvudata
+#pragma redefine_extname t_strerror _xti_strerror
+#pragma redefine_extname t_sync _xti_sync
+#pragma redefine_extname t_sysconf _xti_sysconf
+#pragma redefine_extname t_unbind _xti_unbind
+
+#else /* __PRAGMA_REDEFINE_EXTNAME */
+
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#define t_accept _xti_accept
+#else
+#define t_accept _xti_xns5_accept
+#endif
+#define t_alloc _xti_alloc
+#define t_bind(a,b,c) _xti_bind(a,b,c)
+#define t_close _xti_close
+#define t_connect _xti_connect
+#define t_error _xti_error
+#define t_free _xti_free
+#define t_getinfo _xti_getinfo
+#define t_getstate _xti_getstate
+#define t_getprotaddr _xti_getprotaddr
+#define t_listen _xti_listen
+#define t_look _xti_look
+#define t_open _xti_open
+#define t_optmgmt(a,b,c) _xti_optmgmt(a,b,c)
+#define t_rcv _xti_rcv
+#define t_rcvconnect _xti_rcvconnect
+#define t_rcvdis _xti_rcvdis
+#define t_rcvrel _xti_rcvrel
+#define t_rcvreldata _xti_rcvreldata
+#define t_rcvudata _xti_rcvudata
+#define t_rcvuderr _xti_rcvuderr
+#define t_rcvv _xti_rcvv
+#define t_rcvvudata _xti_rcvvudata
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#define t_snd _xti_snd
+#else
+#define t_snd _xti_xns5_snd
+#endif
+#define t_snddis _xti_snddis
+#define t_sndrel _xti_sndrel
+#define t_sndreldata _xti_sndreldata
+#define t_sndudata _xti_sndudata
+#define t_sndv _xti_sndv
+#define t_sndvudata _xti_sndvudata
+#define t_strerror _xti_strerror
+#define t_sync _xti_sync
+#define t_sysconf _xti_sysconf
+#define t_unbind _xti_unbind
+
+#endif /* __PRAGMA_REDEFINE_EXTNAME */
+
+/*
+ * All the rest of the standard xti.h removed because the structs:
+ * netbuf, t_info, t_opthdr, t_optmgmt, t_bind, t_call, ...
+ * all conflict with definitions in tiuser.h which we need
+ * for the (simulated) kernel interfaces in fake_ktli.c.
+ *
+ * The XTI library functions below would normally be defined by
+ * including tiuser.h after the defines above, which we can't.
+ */
+
+int _xti_accept(int, int, struct t_call *);
+int _xti_xns5_accept(int, int, struct t_call *);
+char *_xti_alloc(int, int, int);
+int _xti_bind(int, struct t_bind *, struct t_bind *);
+int _xti_close(int);
+int _xti_connect(int, struct t_call *, struct t_call *);
+int _xti_error(char *);
+int _xti_free(char *, int);
+int _xti_getinfo(int, struct t_info *);
+int _xti_getprotaddr(int, struct t_bind *, struct t_bind *);
+int _xti_getstate(int);
+int _xti_listen(int, struct t_call *);
+int _xti_look(int);
+int _xti_open(char *, int, struct t_info *);
+int _xti_optmgmt(int, struct t_optmgmt *, struct t_optmgmt *);
+int _xti_rcv(int, char *, unsigned int, int *);
+int _xti_rcvconnect(int, struct t_call *);
+int _xti_rcvdis(int, struct t_discon *);
+int _xti_rcvrel(int);
+int _xti_rcvreldata(int, struct t_discon *);
+int _xti_rcvudata(int, struct t_unitdata *, int *);
+int _xti_rcvuderr(int, struct t_uderr *);
+int _xti_rcvv(int, struct t_iovec *, unsigned int, int *);
+int _xti_rcvvudata(int, struct t_unitdata *, struct t_iovec *,
+ unsigned int, int *);
+int _xti_snd(int, char *, unsigned int, int);
+int _xti_xns5_snd(int, char *, unsigned int, int);
+int _xti_snddis(int, struct t_call *);
+int _xti_sndrel(int);
+int _xti_sndreldata(int, struct t_discon *);
+int _xti_sndudata(int, struct t_unitdata *);
+int _xti_sndv(int, const struct t_iovec *, unsigned int, int);
+int _xti_sndvudata(int, struct t_unitdata *, struct t_iovec *, unsigned int);
+char *_xti_strerror(int);
+int _xti_sync(int);
+int _xti_sysconf(int);
+int _xti_unbind(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XTI_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
new file mode 100644
index 0000000000..24bb8fccbc
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
@@ -0,0 +1,163 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Helper functions for SMB signing using PKCS#11
+ *
+ * There are two implementations of these functions:
+ * This one (for user space) and another for kernel.
+ * See: uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <netsmb/smb_signing.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ mech->mechanism = CKM_MD5;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
+ * Start PKCS#11 session.
+ */
+int
+smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
+{
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = C_DigestInit(*ctxp, mech);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_DigestUpdate(ctx, buf, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ CK_ULONG len = MD5_DIGEST_LENGTH;
+ CK_RV rv;
+
+ rv = C_DigestFinal(ctx, digest16, &len);
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * SMB2 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb2_hmac_getmech(smb_sign_mech_t *mech)
+{
+ mech->mechanism = CKM_SHA256_HMAC;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
+ * Start PKCS#11 session, load the key.
+ */
+int
+smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ CK_OBJECT_HANDLE hkey = 0;
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
+ key, key_len, &hkey);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = C_SignInit(*ctxp, mech, hkey);
+ (void) C_DestroyObject(*ctxp, hkey);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_SignUpdate(ctx, in, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Note, the SMB2 signature is the first 16 bytes of the
+ * 32-byte SHA256 HMAC digest.
+ */
+int
+smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ uint8_t full_digest[SHA256_DIGEST_LENGTH];
+ CK_ULONG len = SHA256_DIGEST_LENGTH;
+ CK_RV rv;
+
+ rv = C_SignFinal(ctx, full_digest, &len);
+ if (rv == CKR_OK)
+ bcopy(full_digest, digest16, 16);
+
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h b/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h
new file mode 100644
index 0000000000..b3d15510be
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h
@@ -0,0 +1,45 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _LIBFKNSMB_H_
+#define _LIBFKNSMB_H_
+
+#include <sys/types.h>
+#include <sys/types32.h>
+#include <sys/cred.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct smb_share;
+
+extern const uint32_t nsmb_version;
+extern void streams_msg_init(void);
+
+int nsmb_drv_init(void);
+int nsmb_drv_fini(void);
+/* These are dev32_t because they're cast to int in user code. */
+int nsmb_drv_ioctl(dev32_t dev, int cmd, intptr_t arg, int flags);
+int nsmb_drv_open(dev32_t *dev, int flags, int otyp);
+int nsmb_drv_close(dev32_t dev, int flags, int otyp);
+int smb_dev2share(int fd, struct smb_share **sspp);
+void nsmb_drv_load(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFKNSMB_H_ */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb b/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb
new file mode 100644
index 0000000000..8ba9f62607
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfknsmb.h>
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
new file mode 100644
index 0000000000..27fbd87b4d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
@@ -0,0 +1,134 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ kmem_avail;
+ kmem_maxavail;
+
+ nsmb_drv_close;
+ nsmb_drv_fini;
+ nsmb_drv_init;
+ nsmb_drv_ioctl;
+ nsmb_drv_load;
+ nsmb_drv_open;
+
+ nsmb_version;
+
+ m_fixhdr;
+ mb_done;
+ mb_init;
+ mb_initm;
+ mb_put_mbchain;
+ mb_put_mbuf;
+ mb_put_mem;
+ mb_put_padbyte;
+ mb_put_uint16le;
+ mb_put_uint32le;
+ mb_put_uint64le;
+ mb_put_uint8;
+ mb_put_uio;
+ mb_reserve;
+
+ md_done;
+ md_get_mbuf;
+ md_get_mem;
+ md_get_uint16le;
+ md_get_uint32le;
+ md_get_uint64le;
+ md_get_uint8;
+ md_initm;
+
+ secpolicy_fs_allowed_mount;
+ secpolicy_vnode_access2;
+ secpolicy_vnode_owner;
+ secpolicy_vnode_setattr;
+ secpolicy_vnode_setdac;
+
+ smb_credinit;
+ smb_credrele;
+ smb_debugmsg { FLAGS = NODIRECT };
+ smb_dev2share;
+ smb_errmsg { FLAGS = NODIRECT };
+ smb_fh_close;
+ smb_fh_create;
+ smb_fh_hold;
+ smb_fh_opened;
+ smb_fh_rele;
+ smb_get_dstring;
+ smb_nt_alloc;
+ smb_nt_done;
+ smb_nt_request;
+ smb_put_dmem;
+ smb_rq_alloc;
+ smb_rq_bend;
+ smb_rq_bstart;
+ smb_rq_done;
+ smb_rq_init;
+ smb_rq_simple;
+ smb_rq_simple_timed;
+ smb_rq_wend;
+ smb_rq_wstart;
+ smb_rwuio;
+ smb_share_kill;
+ smb_share_rele;
+ smb_smb_close;
+ smb_smb_ntcreate;
+ smb_t2_alloc;
+ smb_t2_done;
+ smb_t2_request;
+ smb_time_NT2local;
+ smb_time_local2NT;
+ smb_time_local2server;
+ smb_time_server2local;
+ smb_timo_append;
+ smb_timo_open;
+ smb_timo_read;
+ smb_timo_write;
+
+ smb2_rq_simple;
+ smb2_rq_simple_timed;
+ smb2_smb_close;
+ smb2_smb_ntcreate;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h
new file mode 100644
index 0000000000..68979ca9d4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_FTRACE_H
+#define _SYS_FTRACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Constants used by both asm and non-asm code.
+ */
+
+/*
+ * Flags determining the state of tracing -
+ * both for the "ftrace_state" variable, and for the per-CPU variable
+ * "cpu[N]->cpu_ftrace_state".
+ */
+#define FTRACE_READY 0x00000001
+#define FTRACE_ENABLED 0x00000002
+
+#include <sys/types.h>
+#include <sys/sdt.h>
+
+/*
+ * The record of a single event.
+ * ftrace_record_t;
+ */
+
+#define FTRACE_0(fmt) \
+ DTRACE_PROBE1(ftrace0, char *, fmt)
+#define FTRACE_1(fmt, d1) \
+ DTRACE_PROBE2(ftrace1, char *, fmt, uintptr_t, d1)
+
+// #define FTRACE_START() ftrace_start()
+// #define FTRACE_STOP() ftrace_stop()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FTRACE_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h
new file mode 100644
index 0000000000..64a48897c3
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This header defines an API to map Windows SIDs to
+ * Solaris UID and GIDs and versa visa.
+ */
+
+#ifndef _SYS_KIDMAP_H
+#define _SYS_KIDMAP_H
+
+#include <sys/idmap.h>
+#include <sys/door.h>
+#include <sys/zone.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The ifdef's for these two accomodate duplicate definitions in
+ * lib/libidmap/common/idmap.h (the real one). In this code we
+ * simulate a kernel environment in user space using the real
+ * idmap library, so need to be able to use both headers.
+ */
+
+/* Return status */
+#ifndef _IDMAP_STAT_TYPE
+#define _IDMAP_STAT_TYPE
+typedef int32_t idmap_stat;
+#endif /* _IDMAP_STAT_TYPE */
+
+/* Opaque get handle */
+#ifndef _IDMAP_GET_HANDLE_T
+#define _IDMAP_GET_HANDLE_T
+typedef struct idmap_get_handle idmap_get_handle_t;
+#endif /* _IDMAP_GET_HANDLE_T */
+
+/*
+ * In all the routines a Windows SID is handled as a
+ * string SID prefix plus a RID. For example
+ *
+ * S-1-5-5-12-34-568 will be passed as SID prefix
+ * S-1-5-5-12-34 and RID 568
+ *
+ * Certain routines returns pointers to a SID prefix string.
+ * These strings are stored internally and should not be modified
+ * or freed.
+ */
+
+
+/*
+ * The following routines are simple get ID mapping routines.
+ */
+
+
+idmap_stat
+kidmap_getuidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ uid_t *uid);
+
+idmap_stat
+kidmap_getgidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ gid_t *gid);
+
+idmap_stat
+kidmap_getpidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user);
+
+idmap_stat
+kidmap_getsidbyuid(zone_t *zone, uid_t uid, const char **sid_prefix,
+ uint32_t *rid);
+
+idmap_stat
+kidmap_getsidbygid(zone_t *zone, gid_t gid, const char **sid_prefix,
+ uint32_t *rid);
+
+
+
+/*
+ * The following routines provide a batch interface for mapping IDs.
+ */
+
+/*
+ * Create a batch "get mapping" handle for batch mappings.
+ */
+idmap_get_handle_t *
+kidmap_get_create(zone_t *zone);
+
+/*
+ * These routines queue the request to the "get mapping" handle
+ */
+
+idmap_stat
+kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *uid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ gid_t *gid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+/*
+ * Process the queued "get mapping" requests. The results (i.e.
+ * status and identity) will be available in the data areas
+ * provided by individual requests.
+ */
+idmap_stat
+kidmap_get_mappings(idmap_get_handle_t *get_handle);
+
+/*
+ * Destroy the "get mapping" handle
+ */
+void
+kidmap_get_destroy(idmap_get_handle_t *get_handle);
+
+#ifdef _KERNEL
+/*
+ * Functions that do the hard part of door registration/unregistration
+ * for the idmap_reg()/idmap_unreg() syscalls
+ */
+int idmap_reg_dh(zone_t *zone, door_handle_t dh);
+int idmap_unreg_dh(zone_t *zone, door_handle_t dh);
+
+/*
+ * Function needed by allocids() to ensure only the daemon that owns
+ * the door gets ephemeral IDS
+ */
+door_handle_t idmap_get_door(zone_t *zone);
+
+/*
+ * Function used by system call allocids() to purge the
+ * ID mapping cache
+ */
+void idmap_purge_cache(zone_t *zone);
+
+#endif /* _KERNEL */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_KIDMAP_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h
new file mode 100644
index 0000000000..7ca0d9c3fa
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_POLICY_H
+#define _SYS_POLICY_H
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/fs/snode.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int secpolicy_fs_allowed_mount(const char *);
+int secpolicy_vnode_owner(const cred_t *, uid_t);
+int secpolicy_vnode_access2(const cred_t *, vnode_t *, uid_t, mode_t, mode_t);
+int secpolicy_vnode_setattr(cred_t *, struct vnode *, struct vattr *,
+ const struct vattr *, int, int (void *, int, cred_t *), void *);
+int secpolicy_vnode_setdac(const cred_t *, uid_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_POLICY_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h
new file mode 100644
index 0000000000..c79ea68cec
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SDT_H
+#define _SYS_SDT_H
+
+#include <sys/stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DTrace SDT probes have different signatures in userland than they do in
+ * kernel. If we're compiling for user mode (libfksmbsrv) define them as
+ * either no-op (for the SMB dtrace provider) or libfksmbsrv functions for
+ * the other SDT probe sites.
+ */
+#ifndef _KERNEL
+
+extern void smb_dtrace1(const char *, long);
+extern void smb_dtrace2(const char *, long, long);
+extern void smb_dtrace3(const char *, long, long, long);
+
+/*
+ * These are for the few (specialized) dtrace SDT probes sprinkled
+ * through the smbclnt code. In libfknsmb map these to functions.
+ */
+
+#undef DTRACE_PROBE1
+#define DTRACE_PROBE1(n, t1, a1) \
+ smb_dtrace1(#n, (long)a1)
+
+#undef DTRACE_PROBE2
+#define DTRACE_PROBE2(n, t1, a1, t2, a2) \
+ smb_dtrace2(#n, (long)a1, (long)a2)
+
+#undef DTRACE_PROBE3
+#define DTRACE_PROBE3(n, t1, a1, t2, a2, t3, a3) \
+ smb_dtrace3(#n, (long)a1, (long)a2, (long)a3)
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SYS_SDT_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h
new file mode 100644
index 0000000000..a293118e9d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_STRFT_H
+#define _SYS_STRFT_H
+
+#include <sys/sdt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define FTEV_ALLOCB 0x0000
+#define FTEV_ESBALLOC 0x0001
+#define FTEV_DESBALLOC 0x0002
+#define FTEV_ESBALLOCA 0x0003
+#define FTEV_DESBALLOCA 0x0004
+#define FTEV_ALLOCBIG 0x0005
+#define FTEV_ALLOCBW 0x0006
+#define FTEV_BCALLOCB 0x0007
+#define FTEV_FREEB 0x0008
+#define FTEV_DUPB 0x0009
+#define FTEV_COPYB 0x000A
+
+#define STR_FTALLOC(hpp, e, d) \
+ DTRACE_PROBE3(str__ftalloc, void *, hpp, ushort_t, e, ushort_t, d)
+
+/* Skip the 2nd arg (p) which is: caller() */
+#define STR_FTEVENT_MBLK(mp, p, e, d) \
+ DTRACE_PROBE3(str__ftevent, void *, mp, ushort_t, e, ushort_t, d)
+
+#define str_ftfree(dbp) ((void)(dbp))
+
+extern int str_ftnever, str_ftstack;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_STRFT_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h
new file mode 100644
index 0000000000..f901e79566
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SUNDDI_H
+#define _SYS_SUNDDI_H
+
+/*
+ * Sun Specific DDI definitions (fakekernel version)
+ * The real sunddi.h has become a "kitchen sink" full of
+ * includes we don't want, and lots of places include it.
+ * Rather than fight that battle now, provide this one
+ * with just the str*, mem*, and kiconv* functions.
+ * Some day, re-factor: sunddi.h, systm.h
+ */
+
+#include <sys/isa_defs.h>
+#include <sys/dditypes.h>
+#include <sys/time.h>
+#include <sys/cmn_err.h>
+
+#include <sys/kmem.h>
+#include <sys/nvpair.h>
+#include <sys/thread.h>
+#include <sys/stream.h>
+
+#include <sys/u8_textprep.h>
+#include <sys/kiconv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DDI_SUCCESS (0) /* successful return */
+#define DDI_FAILURE (-1) /* unsuccessful return */
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+extern char *ddi_strdup(const char *str, int flag);
+extern char *strdup(const char *str);
+extern void strfree(char *str);
+
+extern size_t strlen(const char *) __PURE;
+extern size_t strnlen(const char *, size_t) __PURE;
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+
+/* Need to be consistent with <string.h> C++ definition for strchr() */
+#if __cplusplus >= 199711L
+extern const char *strchr(const char *, int);
+#else
+extern char *strchr(const char *, int);
+#endif /* __cplusplus >= 199711L */
+
+#define DDI_STRSAME(s1, s2) ((*(s1) == *(s2)) && (strcmp((s1), (s2)) == 0))
+extern int strcmp(const char *, const char *) __PURE;
+extern int strncmp(const char *, const char *, size_t) __PURE;
+extern char *strncat(char *, const char *, size_t);
+extern size_t strlcat(char *, const char *, size_t);
+extern size_t strlcpy(char *, const char *, size_t);
+extern size_t strspn(const char *, const char *);
+extern size_t strcspn(const char *, const char *);
+extern int bcmp(const void *, const void *, size_t) __PURE;
+extern int stoi(char **);
+extern void numtos(ulong_t, char *);
+extern void bcopy(const void *, void *, size_t);
+extern void bzero(void *, size_t);
+
+extern void *memcpy(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+extern void *memmove(void *, const void *, size_t);
+extern int memcmp(const void *, const void *, size_t) __PURE;
+
+/* Need to be consistent with <string.h> C++ definition for memchr() */
+#if __cplusplus >= 199711L
+extern const void *memchr(const void *, int, size_t);
+#else
+extern void *memchr(const void *, int, size_t);
+#endif /* __cplusplus >= 199711L */
+
+extern int ddi_strtol(const char *, char **, int, long *);
+extern int ddi_strtoul(const char *, char **, int, unsigned long *);
+extern int ddi_strtoll(const char *, char **, int, longlong_t *);
+extern int ddi_strtoull(const char *, char **, int, u_longlong_t *);
+
+extern int ddi_copyin(const void *, void *, size_t, int);
+extern int ddi_copyout(const void *, void *, size_t, int);
+
+/*
+ * kiconv functions and their macros.
+ */
+#define KICONV_IGNORE_NULL (0x0001)
+#define KICONV_REPLACE_INVALID (0x0002)
+
+extern kiconv_t kiconv_open(const char *, const char *);
+extern size_t kiconv(kiconv_t, char **, size_t *, char **, size_t *, int *);
+extern int kiconv_close(kiconv_t);
+extern size_t kiconvstr(const char *, const char *, char *, size_t *, char *,
+ size_t *, int, int *);
+
+int
+ddi_soft_state_init(void **state_p, size_t size, size_t n_items);
+int
+ddi_soft_state_zalloc(void *state, int item);
+void *
+ddi_get_soft_state(void *state, int item);
+void
+ddi_soft_state_free(void *state, int item);
+void
+ddi_soft_state_fini(void **state_p);
+
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SUNDDI_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h
new file mode 100644
index 0000000000..9906f94a12
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h
@@ -0,0 +1,622 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef _SYS_VFS_H
+#define _SYS_VFS_H
+
+#include <sys/zone.h>
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/statvfs.h>
+#include <sys/refstr.h>
+#include <sys/avl.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Data associated with mounted file systems.
+ */
+
+/*
+ * Operations vector. This is used internal to the kernel; file systems
+ * supply their list of operations via vfs_setfsops().
+ */
+
+typedef struct vfsops vfsops_t;
+
+/*
+ * File system identifier. Should be unique (at least per machine).
+ */
+typedef struct {
+ int val[2]; /* file system id type */
+} fsid_t;
+
+/*
+ * File identifier. Should be unique per filesystem on a single
+ * machine. This is typically called by a stateless file server
+ * in order to generate "file handles".
+ *
+ * Many underlying file systems cast a struct fid into other
+ * file system dependent structures which may require 4 byte alignment.
+ * Because a fid starts with a short it may not be 4 byte aligned, the
+ * fid_pad will force the alignment.
+ */
+#define MAXFIDSZ 64
+#define OLD_MAXFIDSZ 16
+
+typedef struct fid {
+ union {
+ long fid_pad;
+ struct {
+ ushort_t len; /* length of data in bytes */
+ char data[MAXFIDSZ]; /* data (variable len) */
+ } _fid;
+ } un;
+} fid_t;
+
+#ifdef _SYSCALL32
+/*
+ * Solaris 64 - use old-style cache format with 32-bit aligned fid for on-disk
+ * struct compatibility.
+ */
+typedef struct fid32 {
+ union {
+ int32_t fid_pad;
+ struct {
+ uint16_t len; /* length of data in bytes */
+ char data[MAXFIDSZ]; /* data (variable len) */
+ } _fid;
+ } un;
+} fid32_t;
+#else /* not _SYSCALL32 */
+#define fid32 fid
+typedef fid_t fid32_t;
+#endif /* _SYSCALL32 */
+
+#define fid_len un._fid.len
+#define fid_data un._fid.data
+
+/*
+ * Structure defining a mount option for a filesystem.
+ * option names are found in mntent.h
+ */
+typedef struct mntopt {
+ char *mo_name; /* option name */
+ char **mo_cancel; /* list of options cancelled by this one */
+ char *mo_arg; /* argument string for this option */
+ int mo_flags; /* flags for this mount option */
+ void *mo_data; /* filesystem specific data */
+} mntopt_t;
+
+/*
+ * Flags that apply to mount options
+ */
+
+#define MO_SET 0x01 /* option is set */
+#define MO_NODISPLAY 0x02 /* option not listed in mnttab */
+#define MO_HASVALUE 0x04 /* option takes a value */
+#define MO_IGNORE 0x08 /* option ignored by parser */
+#define MO_DEFAULT MO_SET /* option is on by default */
+#define MO_TAG 0x10 /* flags a tag set by user program */
+#define MO_EMPTY 0x20 /* empty space in option table */
+
+#define VFS_NOFORCEOPT 0x01 /* honor MO_IGNORE (don't set option) */
+#define VFS_DISPLAY 0x02 /* Turn off MO_NODISPLAY bit for opt */
+#define VFS_NODISPLAY 0x04 /* Turn on MO_NODISPLAY bit for opt */
+#define VFS_CREATEOPT 0x08 /* Create the opt if it's not there */
+
+/*
+ * Structure holding mount option strings for the mounted file system.
+ */
+typedef struct mntopts {
+ uint_t mo_count; /* number of entries in table */
+ mntopt_t *mo_list; /* list of mount options */
+} mntopts_t;
+
+/*
+ * The kstat structures associated with the vopstats are kept in an
+ * AVL tree. This is to avoid the case where a file system does not
+ * use a unique fsid_t for each vfs (e.g., namefs). In order to do
+ * this, we need a structure that the AVL tree can use that also
+ * references the kstat.
+ * Note that the vks_fsid is generated from the value reported by
+ * VFS_STATVFS().
+ */
+typedef struct vskstat_anchor vsk_anchor_t;
+
+extern avl_tree_t vskstat_tree;
+extern kmutex_t vskstat_tree_lock;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+/*
+ * Structure per mounted file system. Each mounted file system has
+ * an array of operations and an instance record.
+ *
+ * The file systems are kept on a doubly linked circular list headed by
+ * "rootvfs".
+ * File system implementations should not access this list;
+ * it's intended for use only in the kernel's vfs layer.
+ *
+ * Each zone also has its own list of mounts, containing filesystems mounted
+ * somewhere within the filesystem tree rooted at the zone's rootpath. The
+ * list is doubly linked to match the global list.
+ *
+ * mnttab locking: the in-kernel mnttab uses the vfs_mntpt, vfs_resource and
+ * vfs_mntopts fields in the vfs_t. mntpt and resource are refstr_ts that
+ * are set at mount time and can only be modified during a remount.
+ * It is safe to read these fields if you can prevent a remount on the vfs,
+ * or through the convenience funcs vfs_getmntpoint() and vfs_getresource().
+ * The mntopts field may only be accessed through the provided convenience
+ * functions, as it is protected by the vfs list lock. Modifying a mount
+ * option requires grabbing the vfs list write lock, which can be a very
+ * high latency lock.
+ */
+struct zone; /* from zone.h */
+struct fem_head; /* from fem.h */
+
+typedef struct vfs {
+ struct vfs *vfs_next; /* next VFS in VFS list */
+ struct vfs *vfs_prev; /* prev VFS in VFS list */
+
+/* vfs_op should not be used directly. Accessor functions are provided */
+ vfsops_t *vfs_op; /* operations on VFS */
+
+ struct vnode *vfs_vnodecovered; /* vnode mounted on */
+ uint_t vfs_flag; /* flags */
+ uint_t vfs_bsize; /* native block size */
+ int vfs_fstype; /* file system type index */
+ fsid_t vfs_fsid; /* file system id */
+ void *vfs_data; /* private data */
+ dev_t vfs_dev; /* device of mounted VFS */
+ ulong_t vfs_bcount; /* I/O count (accounting) */
+ struct vfs *vfs_list; /* sync list pointer */
+ struct vfs *vfs_hash; /* hash list pointer */
+ ksema_t vfs_reflock; /* mount/unmount/sync lock */
+ uint_t vfs_count; /* vfs reference count */
+ mntopts_t vfs_mntopts; /* options mounted with */
+ refstr_t *vfs_resource; /* mounted resource name */
+ refstr_t *vfs_mntpt; /* mount point name */
+ time_t vfs_mtime; /* time we were mounted */
+ struct vfs_impl *vfs_implp; /* impl specific data */
+ /*
+ * Zones support. Note that the zone that "owns" the mount isn't
+ * necessarily the same as the zone in which the zone is visible.
+ * That is, vfs_zone and (vfs_zone_next|vfs_zone_prev) may refer to
+ * different zones.
+ */
+ struct zone *vfs_zone; /* zone that owns the mount */
+ struct vfs *vfs_zone_next; /* next VFS visible in zone */
+ struct vfs *vfs_zone_prev; /* prev VFS visible in zone */
+
+ struct fem_head *vfs_femhead; /* fs monitoring */
+ uint32_t vfs_lofi_id; /* ID if lofi mount */
+} vfs_t;
+
+#define vfs_featureset vfs_implp->vi_featureset
+#define vfs_vskap vfs_implp->vi_vskap
+#define vfs_fstypevsp vfs_implp->vi_fstypevsp
+#define vfs_vopstats vfs_implp->vi_vopstats
+#define vfs_hrctime vfs_implp->vi_hrctime
+
+#else // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+typedef struct vfs vfs_t;
+
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VFS flags.
+ */
+#define VFS_RDONLY 0x01 /* read-only vfs */
+#define VFS_NOMNTTAB 0x02 /* vfs not seen in mnttab */
+#define VFS_NOSETUID 0x08 /* setuid disallowed */
+#define VFS_REMOUNT 0x10 /* modify mount options only */
+#define VFS_NOTRUNC 0x20 /* does not truncate long file names */
+#define VFS_UNLINKABLE 0x40 /* unlink(2) can be applied to root */
+#define VFS_PXFS 0x80 /* clustering: global fs proxy vfs */
+#define VFS_UNMOUNTED 0x100 /* file system has been unmounted */
+#define VFS_NBMAND 0x200 /* allow non-blocking mandatory locks */
+#define VFS_XATTR 0x400 /* fs supports extended attributes */
+#define VFS_NODEVICES 0x800 /* device-special files disallowed */
+#define VFS_NOEXEC 0x1000 /* executables disallowed */
+#define VFS_STATS 0x2000 /* file system can collect stats */
+#define VFS_XID 0x4000 /* file system supports extended ids */
+
+#define VFS_NORESOURCE "unspecified_resource"
+#define VFS_NOMNTPT "unspecified_mountpoint"
+
+/*
+ * VFS features are implemented as bits set in the vfs_t.
+ * The vfs_feature_t typedef is a 64-bit number that will translate
+ * into an element in an array of bitmaps and a bit in that element.
+ * Developers must not depend on the implementation of this and
+ * need to use vfs_has_feature()/vfs_set_feature() routines.
+ */
+typedef uint64_t vfs_feature_t;
+
+#define VFSFT_XVATTR 0x100000001 /* Supports xvattr for attrs */
+#define VFSFT_CASEINSENSITIVE 0x100000002 /* Supports case-insensitive */
+#define VFSFT_NOCASESENSITIVE 0x100000004 /* NOT case-sensitive */
+#define VFSFT_DIRENTFLAGS 0x100000008 /* Supports dirent flags */
+#define VFSFT_ACLONCREATE 0x100000010 /* Supports ACL on create */
+#define VFSFT_ACEMASKONACCESS 0x100000020 /* Can use ACEMASK for access */
+#define VFSFT_SYSATTR_VIEWS 0x100000040 /* Supports sysattr view i/f */
+#define VFSFT_ACCESS_FILTER 0x100000080 /* dirents filtered by access */
+#define VFSFT_REPARSE 0x100000100 /* Supports reparse point */
+#define VFSFT_ZEROCOPY_SUPPORTED 0x100000200
+ /* Support loaning /returning cache buffer */
+/*
+ * Argument structure for mount(2).
+ *
+ * Flags are defined in <sys/mount.h>.
+ *
+ * Note that if the MS_SYSSPACE bit is set in flags, the pointer fields in
+ * this structure are to be interpreted as kernel addresses. File systems
+ * should be prepared for this possibility.
+ */
+struct mounta {
+ char *spec;
+ char *dir;
+ int flags;
+ char *fstype;
+ char *dataptr;
+ int datalen;
+ char *optptr;
+ int optlen;
+};
+
+/*
+ * Reasons for calling the vfs_mountroot() operation.
+ */
+enum whymountroot { ROOT_INIT, ROOT_REMOUNT, ROOT_UNMOUNT};
+typedef enum whymountroot whymountroot_t;
+
+/*
+ * Reasons for calling the VFS_VNSTATE():
+ */
+enum vntrans {
+ VNTRANS_EXISTS,
+ VNTRANS_IDLED,
+ VNTRANS_RECLAIMED,
+ VNTRANS_DESTROYED
+};
+typedef enum vntrans vntrans_t;
+
+/*
+ * VFS_OPS defines all the vfs operations. It is used to define
+ * the vfsops structure (below) and the fs_func_p union (vfs_opreg.h).
+ */
+#define VFS_OPS \
+ int (*vfs_mount)(vfs_t *, vnode_t *, struct mounta *, cred_t *); \
+ int (*vfs_unmount)(vfs_t *, int, cred_t *); \
+ int (*vfs_root)(vfs_t *, vnode_t **); \
+ int (*vfs_statvfs)(vfs_t *, statvfs64_t *); \
+ int (*vfs_sync)(vfs_t *, short, cred_t *); \
+ int (*vfs_vget)(vfs_t *, vnode_t **, fid_t *); \
+ int (*vfs_mountroot)(vfs_t *, enum whymountroot); \
+ void (*vfs_freevfs)(vfs_t *); \
+ int (*vfs_vnstate)(vfs_t *, vnode_t *, vntrans_t) /* NB: No ";" */
+
+/*
+ * Operations supported on virtual file system.
+ */
+struct vfsops {
+ VFS_OPS; /* Signature of all vfs operations (vfsops) */
+};
+
+extern int fsop_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
+extern int fsop_unmount(vfs_t *, int, cred_t *);
+extern int fsop_root(vfs_t *, vnode_t **);
+extern int fsop_statfs(vfs_t *, statvfs64_t *);
+extern int fsop_sync(vfs_t *, short, cred_t *);
+extern int fsop_vget(vfs_t *, vnode_t **, fid_t *);
+extern int fsop_mountroot(vfs_t *, enum whymountroot);
+extern void fsop_freefs(vfs_t *);
+extern int fsop_sync_by_kind(int, short, cred_t *);
+extern int fsop_vnstate(vfs_t *, vnode_t *, vntrans_t);
+
+#define VFS_MOUNT(vfsp, mvp, uap, cr) fsop_mount(vfsp, mvp, uap, cr)
+#define VFS_UNMOUNT(vfsp, flag, cr) fsop_unmount(vfsp, flag, cr)
+#define VFS_ROOT(vfsp, vpp) fsop_root(vfsp, vpp)
+#define VFS_STATVFS(vfsp, sp) fsop_statfs(vfsp, sp)
+#define VFS_SYNC(vfsp, flag, cr) fsop_sync(vfsp, flag, cr)
+#define VFS_VGET(vfsp, vpp, fidp) fsop_vget(vfsp, vpp, fidp)
+#define VFS_MOUNTROOT(vfsp, init) fsop_mountroot(vfsp, init)
+#define VFS_FREEVFS(vfsp) fsop_freefs(vfsp)
+#define VFS_VNSTATE(vfsp, vn, ns) fsop_vnstate(vfsp, vn, ns)
+
+#define VFSNAME_MOUNT "mount"
+#define VFSNAME_UNMOUNT "unmount"
+#define VFSNAME_ROOT "root"
+#define VFSNAME_STATVFS "statvfs"
+#define VFSNAME_SYNC "sync"
+#define VFSNAME_VGET "vget"
+#define VFSNAME_MOUNTROOT "mountroot"
+#define VFSNAME_FREEVFS "freevfs"
+#define VFSNAME_VNSTATE "vnstate"
+/*
+ * Filesystem type switch table.
+ */
+
+typedef struct vfssw {
+ char *vsw_name; /* type name -- max len _ST_FSTYPSZ */
+ int (*vsw_init) (int, char *);
+ /* init routine (for non-loadable fs only) */
+ int vsw_flag; /* flags */
+ mntopts_t vsw_optproto; /* mount options table prototype */
+ uint_t vsw_count; /* count of references */
+ kmutex_t vsw_lock; /* lock to protect vsw_count */
+ vfsops_t vsw_vfsops; /* filesystem operations vector */
+} vfssw_t;
+
+/*
+ * Filesystem type definition record. All file systems must export a record
+ * of this type through their modlfs structure. N.B., changing the version
+ * number requires a change in sys/modctl.h.
+ */
+
+typedef struct vfsdef_v5 {
+ int def_version; /* structure version, must be first */
+ char *name; /* filesystem type name */
+ int (*init) (int, char *); /* init routine */
+ int flags; /* filesystem flags */
+ mntopts_t *optproto; /* mount options table prototype */
+} vfsdef_v5;
+
+typedef struct vfsdef_v5 vfsdef_t;
+
+enum {
+ VFSDEF_VERSION = 5
+};
+
+/* Specific to libfksmbfs */
+int fake_installfs(vfsdef_t *);
+int fake_removefs(vfsdef_t *);
+
+/*
+ * flags for vfssw and vfsdef
+ */
+#define VSW_HASPROTO 0x01 /* struct has a mount options prototype */
+#define VSW_CANRWRO 0x02 /* file system can transition from rw to ro */
+#define VSW_CANREMOUNT 0x04 /* file system supports remounts */
+#define VSW_NOTZONESAFE 0x08 /* zone_enter(2) should fail for these files */
+#define VSW_VOLATILEDEV 0x10 /* vfs_dev can change each time fs is mounted */
+#define VSW_STATS 0x20 /* file system can collect stats */
+#define VSW_XID 0x40 /* file system supports extended ids */
+#define VSW_CANLOFI 0x80 /* file system supports lofi mounts */
+#define VSW_ZMOUNT 0x100 /* file system always allowed in a zone */
+#define VSW_MOUNTDEV 0x200 /* file system is mounted via device path */
+
+#define VSW_INSTALLED 0x8000 /* this vsw is associated with a file system */
+
+/*
+ * A flag for vfs_setpath().
+ */
+#define VFSSP_VERBATIM 0x1 /* do not prefix the supplied path */
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * Private vfs data, NOT to be used by a file system implementation.
+ */
+
+#define VFS_FEATURE_MAXSZ 4
+
+typedef struct vfs_impl {
+ /* Counted array - Bitmap of vfs features */
+ uint32_t vi_featureset[VFS_FEATURE_MAXSZ];
+ /*
+ * Support for statistics on the vnode operations
+ */
+ vsk_anchor_t *vi_vskap; /* anchor for vopstats' kstat */
+ vopstats_t *vi_fstypevsp; /* ptr to per-fstype vopstats */
+ vopstats_t vi_vopstats; /* per-mount vnode op stats */
+
+ timespec_t vi_hrctime; /* High-res creation time */
+
+ zone_ref_t vi_zone_ref; /* reference to zone */
+} vfs_impl_t;
+
+/*
+ * Public operations.
+ */
+struct umounta;
+struct statvfsa;
+struct fstatvfsa;
+
+void vfs_freevfsops(vfsops_t *);
+int vfs_freevfsops_by_type(int);
+void vfs_setops(vfs_t *, vfsops_t *);
+vfsops_t *vfs_getops(vfs_t *vfsp);
+int vfs_matchops(vfs_t *, vfsops_t *);
+int vfs_can_sync(vfs_t *vfsp);
+vfs_t *vfs_alloc(int);
+void vfs_free(vfs_t *);
+void vfs_init(vfs_t *vfsp, vfsops_t *, void *);
+void vfsimpl_setup(vfs_t *vfsp);
+void vfsimpl_teardown(vfs_t *vfsp);
+void vn_exists(vnode_t *);
+void vn_idle(vnode_t *);
+void vn_reclaim(vnode_t *);
+void vn_invalid(vnode_t *);
+
+int rootconf(void);
+int domount(char *, struct mounta *, vnode_t *, struct cred *,
+ struct vfs **);
+int dounmount(struct vfs *, int, cred_t *);
+int vfs_lock(struct vfs *);
+int vfs_rlock(struct vfs *);
+void vfs_lock_wait(struct vfs *);
+void vfs_rlock_wait(struct vfs *);
+void vfs_unlock(struct vfs *);
+int vfs_lock_held(struct vfs *);
+struct _kthread *vfs_lock_owner(struct vfs *);
+void sync(void);
+void vfs_sync(int);
+void vfs_mountroot(void);
+void vfs_add(vnode_t *, struct vfs *, int);
+void vfs_remove(struct vfs *);
+
+/* VFS feature routines */
+void vfs_set_feature(vfs_t *, vfs_feature_t);
+void vfs_clear_feature(vfs_t *, vfs_feature_t);
+int vfs_has_feature(vfs_t *, vfs_feature_t);
+void vfs_propagate_features(vfs_t *, vfs_t *);
+
+/* The following functions are not for general use by filesystems */
+
+void vfs_createopttbl(mntopts_t *, const char *);
+void vfs_copyopttbl(const mntopts_t *, mntopts_t *);
+void vfs_mergeopttbl(const mntopts_t *, const mntopts_t *, mntopts_t *);
+void vfs_freeopttbl(mntopts_t *);
+void vfs_parsemntopts(mntopts_t *, char *, int);
+int vfs_buildoptionstr(const mntopts_t *, char *, int);
+struct mntopt *vfs_hasopt(const mntopts_t *, const char *);
+void vfs_mnttab_modtimeupd(void);
+
+void vfs_clearmntopt(struct vfs *, const char *);
+void vfs_setmntopt(struct vfs *, const char *, const char *, int);
+void vfs_setresource(struct vfs *, const char *, uint32_t);
+void vfs_setmntpoint(struct vfs *, const char *, uint32_t);
+refstr_t *vfs_getresource(const struct vfs *);
+refstr_t *vfs_getmntpoint(const struct vfs *);
+int vfs_optionisset(const struct vfs *, const char *, char **);
+int vfs_settag(uint_t, uint_t, const char *, const char *, cred_t *);
+int vfs_clrtag(uint_t, uint_t, const char *, const char *, cred_t *);
+void vfs_syncall(void);
+void vfsinit(void);
+void vfs_unmountall(void);
+void vfs_make_fsid(fsid_t *, dev_t, int);
+void vfs_addmip(dev_t, struct vfs *);
+void vfs_delmip(struct vfs *);
+int vfs_devismounted(dev_t);
+int vfs_devmounting(dev_t, struct vfs *);
+int vfs_opsinuse(vfsops_t *);
+struct vfs *getvfs(fsid_t *);
+struct vfs *vfs_dev2vfsp(dev_t);
+struct vfs *vfs_mntpoint2vfsp(const char *);
+struct vfssw *allocate_vfssw(const char *);
+struct vfssw *vfs_getvfssw(const char *);
+struct vfssw *vfs_getvfsswbyname(const char *);
+struct vfssw *vfs_getvfsswbyvfsops(vfsops_t *);
+void vfs_refvfssw(struct vfssw *);
+void vfs_unrefvfssw(struct vfssw *);
+uint_t vf_to_stf(uint_t);
+void vfs_mnttab_modtime(timespec_t *);
+void vfs_mnttab_poll(timespec_t *, struct pollhead **);
+
+void vfs_list_lock(void);
+void vfs_list_read_lock(void);
+void vfs_list_unlock(void);
+void vfs_list_add(struct vfs *);
+void vfs_list_remove(struct vfs *);
+void vfs_hold(vfs_t *vfsp);
+void vfs_rele(vfs_t *vfsp);
+void fs_freevfs(vfs_t *);
+void vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype);
+
+int vfs_zone_change_safe(vfs_t *);
+
+int vfs_get_lofi(vfs_t *, vnode_t **);
+
+#define VFSHASH(maj, min) (((int)((maj)+(min))) & (vfshsz - 1))
+#define VFS_ON_LIST(vfsp) \
+ ((vfsp)->vfs_next != (vfsp) && (vfsp)->vfs_next != NULL)
+
+/*
+ * Globals.
+ */
+
+extern struct vfssw vfssw[]; /* table of filesystem types */
+extern krwlock_t vfssw_lock;
+extern char rootfstype[]; /* name of root fstype */
+extern const int nfstype; /* # of elements in vfssw array */
+extern vfsops_t *EIO_vfsops; /* operations for vfs being torn-down */
+
+/*
+ * The following variables are private to the the kernel's vfs layer. File
+ * system implementations should not access them.
+ */
+extern struct vfs *rootvfs; /* ptr to root vfs structure */
+typedef struct {
+ struct vfs *rvfs_head; /* head vfs in chain */
+ kmutex_t rvfs_lock; /* mutex protecting this chain */
+ uint32_t rvfs_len; /* length of this chain */
+} rvfs_t;
+extern rvfs_t *rvfs_list;
+extern int vfshsz; /* # of elements in rvfs_head array */
+extern const mntopts_t vfs_mntopts; /* globally recognized options */
+
+#endif /* defined(_KERNEL) */
+
+#define VFS_HOLD(vfsp) { \
+ vfs_hold(vfsp); \
+}
+
+#define VFS_RELE(vfsp) { \
+ vfs_rele(vfsp); \
+}
+
+#define VFS_INIT(vfsp, op, data) { \
+ vfs_init((vfsp), (op), (data)); \
+}
+
+
+#define VFS_INSTALLED(vfsswp) (((vfsswp)->vsw_flag & VSW_INSTALLED) != 0)
+#define ALLOCATED_VFSSW(vswp) ((vswp)->vsw_name[0] != '\0')
+#define RLOCK_VFSSW() (rw_enter(&vfssw_lock, RW_READER))
+#define RUNLOCK_VFSSW() (rw_exit(&vfssw_lock))
+#define WLOCK_VFSSW() (rw_enter(&vfssw_lock, RW_WRITER))
+#define WUNLOCK_VFSSW() (rw_exit(&vfssw_lock))
+#define VFSSW_LOCKED() (RW_LOCK_HELD(&vfssw_lock))
+#define VFSSW_WRITE_LOCKED() (RW_WRITE_HELD(&vfssw_lock))
+/*
+ * VFS_SYNC flags.
+ */
+#define SYNC_ATTR 0x01 /* sync attributes only */
+#define SYNC_CLOSE 0x02 /* close open file */
+#define SYNC_ALL 0x04 /* force to sync all fs */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VFS_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h
new file mode 100644
index 0000000000..cdb6c9c6c5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_VFS_OPREG_H
+#define _SYS_VFS_OPREG_H
+
+#include <sys/vfs.h>
+#include <sys/fem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * The following union allows us to use C99's "designated initializer"
+ * feature so that we can have strong typechecking for the operations
+ * used in the the fs_operation_def structures.
+ */
+
+typedef union fs_func {
+ fs_generic_func_p fs_generic; /* Generic function signature */
+ int (*error)(); /* Signature of error function */
+ VFS_OPS; /* Signatures of all vfs operations (vfsops) */
+ VNODE_OPS; /* Signatures of all vnode operations (vops) */
+ FEM_OPS; /* Signatures of all FEM operations (femops) */
+ FSEM_OPS; /* Signatures of all FSEM ops (fsemops) */
+} fs_func_p;
+
+/*
+ * File systems use arrays of fs_operation_def structures to form
+ * name/value pairs of operations. These arrays get passed to:
+ *
+ * - vn_make_ops() to create vnodeops
+ * - vfs_makefsops()/vfs_setfsops() to create vfsops.
+ */
+typedef struct fs_operation_def {
+ char *name; /* name of operation (NULL at end) */
+ fs_func_p func; /* function implementing operation */
+} fs_operation_def_t;
+
+/*
+ * The operation registration mechanism uses two master tables of operations:
+ * one for vnode operations (vn_ops_table[]) and one for vfs operations
+ * (vfs_ops_table[]). These tables are arrays of fs_operation_trans_def
+ * structures. They contain all of the information necessary for the system
+ * to populate an operations structure (e.g., vnodeops, vfsops).
+ *
+ * File systems call registration routines (vfs_setfsops(), vfs_makefsops(),
+ * and vn_make_ops()) and pass in their operations specification tables
+ * (arrays of fs_operation_def structures). These routines use the master
+ * table(s) of operations to build a vnodeops or vfsops structure.
+ */
+typedef struct fs_operation_trans_def {
+ char *name; /* name of operation (NULL at end) */
+ int offset; /* byte offset within ops vector */
+ fs_generic_func_p defaultFunc; /* default function */
+ fs_generic_func_p errorFunc; /* error function */
+} fs_operation_trans_def_t;
+
+/*
+ * Generic operations vector types (used for vfs/vnode ops registration).
+ */
+
+extern int fs_default(); /* "default" function placeholder */
+extern int fs_error(); /* "error" function placeholder */
+
+int fs_build_vector(void *vector, int *unused_ops,
+ const fs_operation_trans_def_t *translation,
+ const fs_operation_def_t *operations);
+
+/*
+ * Public operations.
+ */
+
+int vn_make_ops(const char *, const struct fs_operation_def *,
+ vnodeops_t **);
+void vn_freevnodeops(vnodeops_t *);
+
+int vfs_setfsops(int, const fs_operation_def_t *, vfsops_t **);
+int vfs_makefsops(const fs_operation_def_t *, vfsops_t **);
+void vfs_freevfsops(vfsops_t *);
+int vfs_freevfsops_by_type(int);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VFS_OPREG_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h
new file mode 100644
index 0000000000..33e84e68f2
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h
@@ -0,0 +1,1452 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _SYS_VNODE_H
+#define _SYS_VNODE_H
+
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/time_impl.h>
+#include <sys/cred.h>
+#include <sys/uio.h>
+#include <sys/resource.h>
+#include <vm/seg_enum.h>
+#include <sys/kstat.h>
+#include <sys/kmem.h>
+#include <sys/list.h>
+#include <sys/avl.h>
+#ifdef _KERNEL
+#include <sys/rwstlock.h>
+#include <sys/buf.h>
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * Statistics for all vnode operations.
+ * All operations record number of ops (since boot/mount/zero'ed).
+ * Certain I/O operations (read, write, readdir) also record number
+ * of bytes transferred.
+ * This appears in two places in the system: one is embedded in each
+ * vfs_t. There is also an array of vopstats_t structures allocated
+ * on a per-fstype basis.
+ */
+
+#define VOPSTATS_STR "vopstats_" /* Initial string for vopstat kstats */
+
+typedef struct vopstats {
+ kstat_named_t nopen; /* VOP_OPEN */
+ kstat_named_t nclose; /* VOP_CLOSE */
+ kstat_named_t nread; /* VOP_READ */
+ kstat_named_t read_bytes;
+ kstat_named_t nwrite; /* VOP_WRITE */
+ kstat_named_t write_bytes;
+ kstat_named_t nioctl; /* VOP_IOCTL */
+ kstat_named_t nsetfl; /* VOP_SETFL */
+ kstat_named_t ngetattr; /* VOP_GETATTR */
+ kstat_named_t nsetattr; /* VOP_SETATTR */
+ kstat_named_t naccess; /* VOP_ACCESS */
+ kstat_named_t nlookup; /* VOP_LOOKUP */
+ kstat_named_t ncreate; /* VOP_CREATE */
+ kstat_named_t nremove; /* VOP_REMOVE */
+ kstat_named_t nlink; /* VOP_LINK */
+ kstat_named_t nrename; /* VOP_RENAME */
+ kstat_named_t nmkdir; /* VOP_MKDIR */
+ kstat_named_t nrmdir; /* VOP_RMDIR */
+ kstat_named_t nreaddir; /* VOP_READDIR */
+ kstat_named_t readdir_bytes;
+ kstat_named_t nsymlink; /* VOP_SYMLINK */
+ kstat_named_t nreadlink; /* VOP_READLINK */
+ kstat_named_t nfsync; /* VOP_FSYNC */
+ kstat_named_t ninactive; /* VOP_INACTIVE */
+ kstat_named_t nfid; /* VOP_FID */
+ kstat_named_t nrwlock; /* VOP_RWLOCK */
+ kstat_named_t nrwunlock; /* VOP_RWUNLOCK */
+ kstat_named_t nseek; /* VOP_SEEK */
+ kstat_named_t ncmp; /* VOP_CMP */
+ kstat_named_t nfrlock; /* VOP_FRLOCK */
+ kstat_named_t nspace; /* VOP_SPACE */
+ kstat_named_t nrealvp; /* VOP_REALVP */
+ kstat_named_t ngetpage; /* VOP_GETPAGE */
+ kstat_named_t nputpage; /* VOP_PUTPAGE */
+ kstat_named_t nmap; /* VOP_MAP */
+ kstat_named_t naddmap; /* VOP_ADDMAP */
+ kstat_named_t ndelmap; /* VOP_DELMAP */
+ kstat_named_t npoll; /* VOP_POLL */
+ kstat_named_t ndump; /* VOP_DUMP */
+ kstat_named_t npathconf; /* VOP_PATHCONF */
+ kstat_named_t npageio; /* VOP_PAGEIO */
+ kstat_named_t ndumpctl; /* VOP_DUMPCTL */
+ kstat_named_t ndispose; /* VOP_DISPOSE */
+ kstat_named_t nsetsecattr; /* VOP_SETSECATTR */
+ kstat_named_t ngetsecattr; /* VOP_GETSECATTR */
+ kstat_named_t nshrlock; /* VOP_SHRLOCK */
+ kstat_named_t nvnevent; /* VOP_VNEVENT */
+ kstat_named_t nreqzcbuf; /* VOP_REQZCBUF */
+ kstat_named_t nretzcbuf; /* VOP_RETZCBUF */
+} vopstats_t;
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * The vnode is the focus of all file activity in UNIX.
+ * A vnode is allocated for each active file, each current
+ * directory, each mounted-on file, and the root.
+ *
+ * Each vnode is usually associated with a file-system-specific node (for
+ * UFS, this is the in-memory inode). Generally, a vnode and an fs-node
+ * should be created and destroyed together as a pair.
+ *
+ * If a vnode is reused for a new file, it should be reinitialized by calling
+ * either vn_reinit() or vn_recycle().
+ *
+ * vn_reinit() resets the entire vnode as if it was returned by vn_alloc().
+ * The caller is responsible for setting up the entire vnode after calling
+ * vn_reinit(). This is important when using kmem caching where the vnode is
+ * allocated by a constructor, for instance.
+ *
+ * vn_recycle() is used when the file system keeps some state around in both
+ * the vnode and the associated FS-node. In UFS, for example, the inode of
+ * a deleted file can be reused immediately. The v_data, v_vfsp, v_op, etc.
+ * remains the same but certain fields related to the previous instance need
+ * to be reset. In particular:
+ * v_femhead
+ * v_path
+ * v_rdcnt, v_wrcnt
+ * v_mmap_read, v_mmap_write
+ */
+
+/*
+ * vnode types. VNON means no type. These values are unrelated to
+ * values in on-disk inodes.
+ */
+typedef enum vtype {
+ VNON = 0,
+ VREG = 1,
+ VDIR = 2,
+ VBLK = 3,
+ VCHR = 4,
+ VLNK = 5,
+ VFIFO = 6,
+ VDOOR = 7,
+ VPROC = 8,
+ VSOCK = 9,
+ VPORT = 10,
+ VBAD = 11
+} vtype_t;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VSD - Vnode Specific Data
+ * Used to associate additional private data with a vnode.
+ */
+struct vsd_node {
+ list_node_t vs_nodes; /* list of all VSD nodes */
+ uint_t vs_nkeys; /* entries in value array */
+ void **vs_value; /* array of value/key */
+};
+
+/*
+ * Many of the fields in the vnode are read-only once they are initialized
+ * at vnode creation time. Other fields are protected by locks.
+ *
+ * IMPORTANT: vnodes should be created ONLY by calls to vn_alloc(). They
+ * may not be embedded into the file-system specific node (inode). The
+ * size of vnodes may change.
+ *
+ * The v_lock protects:
+ * v_flag
+ * v_stream
+ * v_count
+ * v_shrlocks
+ * v_path
+ * v_vsd
+ * v_xattrdir
+ *
+ * A special lock (implemented by vn_vfswlock in vnode.c) protects:
+ * v_vfsmountedhere
+ *
+ * The global flock_lock mutex (in flock.c) protects:
+ * v_filocks
+ *
+ * IMPORTANT NOTE:
+ *
+ * The following vnode fields are considered public and may safely be
+ * accessed by file systems or other consumers:
+ *
+ * v_lock
+ * v_flag
+ * v_count
+ * v_data
+ * v_vfsp
+ * v_stream
+ * v_type
+ * v_rdev
+ *
+ * ALL OTHER FIELDS SHOULD BE ACCESSED ONLY BY THE OWNER OF THAT FIELD.
+ * In particular, file systems should not access other fields; they may
+ * change or even be removed. The functionality which was once provided
+ * by these fields is available through vn_* functions.
+ */
+
+struct fem_head; /* from fem.h */
+
+typedef struct vnode {
+ kmutex_t v_lock; /* protects vnode fields */
+ uint_t v_flag; /* vnode flags (see below) */
+ uint_t v_count; /* reference count */
+ void *v_data; /* private data for fs */
+ struct vfs *v_vfsp; /* ptr to containing VFS */
+ struct stdata *v_stream; /* associated stream */
+ enum vtype v_type; /* vnode type */
+ dev_t v_rdev; /* device (VCHR, VBLK) */
+
+ /* PRIVATE FIELDS BELOW - DO NOT USE */
+
+ struct vfs *v_vfsmountedhere; /* ptr to vfs mounted here */
+ struct vnodeops *v_op; /* vnode operations */
+ krwlock_t v_nbllock; /* sync for NBMAND locks */
+ char *v_path; /* cached path */
+ uint_t v_rdcnt; /* open for read count (VREG only) */
+ uint_t v_wrcnt; /* open for write count (VREG only) */
+ struct vnode *v_xattrdir; /* unnamed extended attr dir (GFS) */
+
+ /* Private to the fake vnode impl. */
+
+ int v_fd;
+ dev_t v_st_dev;
+ ino_t v_st_ino;
+ avl_node_t v_avl_node;
+ int v_vfsrlocks;
+} vnode_t;
+
+#define IS_DEVVP(vp) \
+ ((vp)->v_type == VCHR || (vp)->v_type == VBLK || (vp)->v_type == VFIFO)
+
+#define VNODE_ALIGN 16
+
+/*
+ * vnode flags.
+ */
+#define VROOT 0x01 /* root of its file system */
+#define VNOCACHE 0x02 /* don't keep cache pages on vnode */
+#define VNOMAP 0x04 /* file cannot be mapped/faulted */
+#define VDUP 0x08 /* file should be dup'ed rather then opened */
+#define VNOSWAP 0x10 /* file cannot be used as virtual swap device */
+#define VNOMOUNT 0x20 /* file cannot be covered by mount */
+#define VISSWAP 0x40 /* vnode is being used for swap */
+#define VSWAPLIKE 0x80 /* vnode acts like swap (but may not be) */
+
+#define IS_SWAPVP(vp) (((vp)->v_flag & (VISSWAP | VSWAPLIKE)) != 0)
+
+#else // defined(_KERNEL) || defined(_FAKE_KERNEL)
+typedef struct vnode vnode_t;
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+#if defined(_KERNEL)
+typedef struct vn_vfslocks_entry {
+ rwstlock_t ve_lock;
+ void *ve_vpvfs;
+ struct vn_vfslocks_entry *ve_next;
+ uint32_t ve_refcnt;
+ char pad[64 - sizeof (rwstlock_t) - 2 * sizeof (void *) - \
+ sizeof (uint32_t)];
+} vn_vfslocks_entry_t;
+#endif /* _KERNEL */
+
+/*
+ * The following two flags are used to lock the v_vfsmountedhere field
+ */
+#define VVFSLOCK 0x100
+#define VVFSWAIT 0x200
+
+/*
+ * Used to serialize VM operations on a vnode
+ */
+#define VVMLOCK 0x400
+
+/*
+ * Tell vn_open() not to fail a directory open for writing but
+ * to go ahead and call VOP_OPEN() to let the filesystem check.
+ */
+#define VDIROPEN 0x800
+
+/*
+ * Flag to let the VM system know that this file is most likely a binary
+ * or shared library since it has been mmap()ed EXEC at some time.
+ */
+#define VVMEXEC 0x1000
+
+#define VPXFS 0x2000 /* clustering: global fs proxy vnode */
+
+#define IS_PXFSVP(vp) ((vp)->v_flag & VPXFS)
+
+#define V_XATTRDIR 0x4000 /* attribute unnamed directory */
+
+#define IS_XATTRDIR(vp) ((vp)->v_flag & V_XATTRDIR)
+
+#define V_LOCALITY 0x8000 /* whether locality aware */
+
+/*
+ * Flag that indicates the VM should maintain the v_pages list with all modified
+ * pages on one end and unmodified pages at the other. This makes finding dirty
+ * pages to write back to disk much faster at the expense of taking a minor
+ * fault on the first store instruction which touches a writable page.
+ */
+#define VMODSORT (0x10000)
+#define IS_VMODSORT(vp) \
+ (pvn_vmodsort_supported != 0 && ((vp)->v_flag & VMODSORT) != 0)
+
+#define VISSWAPFS 0x20000 /* vnode is being used for swapfs */
+
+/*
+ * The mdb memstat command assumes that IS_SWAPFSVP only uses the
+ * vnode's v_flag field. If this changes, cache the additional
+ * fields in mdb; see vn_get in mdb/common/modules/genunix/memory.c
+ */
+#define IS_SWAPFSVP(vp) (((vp)->v_flag & VISSWAPFS) != 0)
+
+#define V_SYSATTR 0x40000 /* vnode is a GFS system attribute */
+
+/*
+ * Vnode attributes. A bit-mask is supplied as part of the
+ * structure to indicate the attributes the caller wants to
+ * set (setattr) or extract (getattr).
+ */
+
+/*
+ * Note that va_nodeid and va_nblocks are 64bit data type.
+ * We support large files over NFSV3. With Solaris client and
+ * Server that generates 64bit ino's and sizes these fields
+ * will overflow if they are 32 bit sizes.
+ */
+
+typedef struct vattr {
+ uint_t va_mask; /* bit-mask of attributes */
+ vtype_t va_type; /* vnode type (for create) */
+ mode_t va_mode; /* file access mode */
+ uid_t va_uid; /* owner user id */
+ gid_t va_gid; /* owner group id */
+ dev_t va_fsid; /* file system id (dev for now) */
+ u_longlong_t va_nodeid; /* node id */
+ nlink_t va_nlink; /* number of references to file */
+ u_offset_t va_size; /* file size in bytes */
+ timestruc_t va_atime; /* time of last access */
+ timestruc_t va_mtime; /* time of last modification */
+ timestruc_t va_ctime; /* time of last status change */
+ dev_t va_rdev; /* device the file represents */
+ uint_t va_blksize; /* fundamental block size */
+ u_longlong_t va_nblocks; /* # of blocks allocated */
+ uint_t va_seq; /* sequence number */
+} vattr_t;
+
+#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
+
+/*
+ * Structure of all optional attributes.
+ */
+typedef struct xoptattr {
+ timestruc_t xoa_createtime; /* Create time of file */
+ uint8_t xoa_archive;
+ uint8_t xoa_system;
+ uint8_t xoa_readonly;
+ uint8_t xoa_hidden;
+ uint8_t xoa_nounlink;
+ uint8_t xoa_immutable;
+ uint8_t xoa_appendonly;
+ uint8_t xoa_nodump;
+ uint8_t xoa_opaque;
+ uint8_t xoa_av_quarantined;
+ uint8_t xoa_av_modified;
+ uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
+ uint64_t xoa_generation;
+ uint8_t xoa_offline;
+ uint8_t xoa_sparse;
+} xoptattr_t;
+
+/*
+ * The xvattr structure is really a variable length structure that
+ * is made up of:
+ * - The classic vattr_t (xva_vattr)
+ * - a 32 bit quantity (xva_mapsize) that specifies the size of the
+ * attribute bitmaps in 32 bit words.
+ * - A pointer to the returned attribute bitmap (needed because the
+ * previous element, the requested attribute bitmap) is variable lenth.
+ * - The requested attribute bitmap, which is an array of 32 bit words.
+ * Callers use the XVA_SET_REQ() macro to set the bits corresponding to
+ * the attributes that are being requested.
+ * - The returned attribute bitmap, which is an array of 32 bit words.
+ * File systems that support optional attributes use the XVA_SET_RTN()
+ * macro to set the bits corresponding to the attributes that are being
+ * returned.
+ * - The xoptattr_t structure which contains the attribute values
+ *
+ * xva_mapsize determines how many words in the attribute bitmaps.
+ * Immediately following the attribute bitmaps is the xoptattr_t.
+ * xva_getxoptattr() is used to get the pointer to the xoptattr_t
+ * section.
+ */
+
+#define XVA_MAPSIZE 3 /* Size of attr bitmaps */
+#define XVA_MAGIC 0x78766174 /* Magic # for verification */
+
+/*
+ * The xvattr structure is an extensible structure which permits optional
+ * attributes to be requested/returned. File systems may or may not support
+ * optional attributes. They do so at their own discretion but if they do
+ * support optional attributes, they must register the VFSFT_XVATTR feature
+ * so that the optional attributes can be set/retrived.
+ *
+ * The fields of the xvattr structure are:
+ *
+ * xva_vattr - The first element of an xvattr is a legacy vattr structure
+ * which includes the common attributes. If AT_XVATTR is set in the va_mask
+ * then the entire structure is treated as an xvattr. If AT_XVATTR is not
+ * set, then only the xva_vattr structure can be used.
+ *
+ * xva_magic - 0x78766174 (hex for "xvat"). Magic number for verification.
+ *
+ * xva_mapsize - Size of requested and returned attribute bitmaps.
+ *
+ * xva_rtnattrmapp - Pointer to xva_rtnattrmap[]. We need this since the
+ * size of the array before it, xva_reqattrmap[], could change which means
+ * the location of xva_rtnattrmap[] could change. This will allow unbundled
+ * file systems to find the location of xva_rtnattrmap[] when the sizes change.
+ *
+ * xva_reqattrmap[] - Array of requested attributes. Attributes are
+ * represented by a specific bit in a specific element of the attribute
+ * map array. Callers set the bits corresponding to the attributes
+ * that the caller wants to get/set.
+ *
+ * xva_rtnattrmap[] - Array of attributes that the file system was able to
+ * process. Not all file systems support all optional attributes. This map
+ * informs the caller which attributes the underlying file system was able
+ * to set/get. (Same structure as the requested attributes array in terms
+ * of each attribute corresponding to specific bits and array elements.)
+ *
+ * xva_xoptattrs - Structure containing values of optional attributes.
+ * These values are only valid if the corresponding bits in xva_reqattrmap
+ * are set and the underlying file system supports those attributes.
+ */
+typedef struct xvattr {
+ vattr_t xva_vattr; /* Embedded vattr structure */
+ uint32_t xva_magic; /* Magic Number */
+ uint32_t xva_mapsize; /* Size of attr bitmap (32-bit words) */
+ uint32_t *xva_rtnattrmapp; /* Ptr to xva_rtnattrmap[] */
+ uint32_t xva_reqattrmap[XVA_MAPSIZE]; /* Requested attrs */
+ uint32_t xva_rtnattrmap[XVA_MAPSIZE]; /* Returned attrs */
+ xoptattr_t xva_xoptattrs; /* Optional attributes */
+} xvattr_t;
+
+#ifdef _SYSCALL32
+/*
+ * For bigtypes time_t changed to 64 bit on the 64-bit kernel.
+ * Define an old version for user/kernel interface
+ */
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct vattr32 {
+ uint32_t va_mask; /* bit-mask of attributes */
+ vtype_t va_type; /* vnode type (for create) */
+ mode32_t va_mode; /* file access mode */
+ uid32_t va_uid; /* owner user id */
+ gid32_t va_gid; /* owner group id */
+ dev32_t va_fsid; /* file system id (dev for now) */
+ u_longlong_t va_nodeid; /* node id */
+ nlink_t va_nlink; /* number of references to file */
+ u_offset_t va_size; /* file size in bytes */
+ timestruc32_t va_atime; /* time of last access */
+ timestruc32_t va_mtime; /* time of last modification */
+ timestruc32_t va_ctime; /* time of last status change */
+ dev32_t va_rdev; /* device the file represents */
+ uint32_t va_blksize; /* fundamental block size */
+ u_longlong_t va_nblocks; /* # of blocks allocated */
+ uint32_t va_seq; /* sequence number */
+} vattr32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+#else /* not _SYSCALL32 */
+#define vattr32 vattr
+typedef vattr_t vattr32_t;
+#endif /* _SYSCALL32 */
+
+/*
+ * Attributes of interest to the caller of setattr or getattr.
+ */
+#define AT_TYPE 0x00001
+#define AT_MODE 0x00002
+#define AT_UID 0x00004
+#define AT_GID 0x00008
+#define AT_FSID 0x00010
+#define AT_NODEID 0x00020
+#define AT_NLINK 0x00040
+#define AT_SIZE 0x00080
+#define AT_ATIME 0x00100
+#define AT_MTIME 0x00200
+#define AT_CTIME 0x00400
+#define AT_RDEV 0x00800
+#define AT_BLKSIZE 0x01000
+#define AT_NBLOCKS 0x02000
+/* 0x04000 */ /* unused */
+#define AT_SEQ 0x08000
+/*
+ * If AT_XVATTR is set then there are additional bits to process in
+ * the xvattr_t's attribute bitmap. If this is not set then the bitmap
+ * MUST be ignored. Note that this bit must be set/cleared explicitly.
+ * That is, setting AT_ALL will NOT set AT_XVATTR.
+ */
+#define AT_XVATTR 0x10000
+
+#define AT_ALL (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|\
+ AT_NLINK|AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|\
+ AT_RDEV|AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
+
+#define AT_STAT (AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|AT_NLINK|\
+ AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|AT_TYPE)
+
+#define AT_TIMES (AT_ATIME|AT_MTIME|AT_CTIME)
+
+#define AT_NOSET (AT_NLINK|AT_RDEV|AT_FSID|AT_NODEID|AT_TYPE|\
+ AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
+
+/*
+ * Attribute bits used in the extensible attribute's (xva's) attribute
+ * bitmaps. Note that the bitmaps are made up of a variable length number
+ * of 32-bit words. The convention is to use XAT{n}_{attrname} where "n"
+ * is the element in the bitmap (starting at 1). This convention is for
+ * the convenience of the maintainer to keep track of which element each
+ * attribute belongs to.
+ *
+ * NOTE THAT CONSUMERS MUST *NOT* USE THE XATn_* DEFINES DIRECTLY. CONSUMERS
+ * MUST USE THE XAT_* DEFINES.
+ */
+#define XAT0_INDEX 0LL /* Index into bitmap for XAT0 attrs */
+#define XAT0_CREATETIME 0x00000001 /* Create time of file */
+#define XAT0_ARCHIVE 0x00000002 /* Archive */
+#define XAT0_SYSTEM 0x00000004 /* System */
+#define XAT0_READONLY 0x00000008 /* Readonly */
+#define XAT0_HIDDEN 0x00000010 /* Hidden */
+#define XAT0_NOUNLINK 0x00000020 /* Nounlink */
+#define XAT0_IMMUTABLE 0x00000040 /* immutable */
+#define XAT0_APPENDONLY 0x00000080 /* appendonly */
+#define XAT0_NODUMP 0x00000100 /* nodump */
+#define XAT0_OPAQUE 0x00000200 /* opaque */
+#define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */
+#define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */
+#define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */
+#define XAT0_REPARSE 0x00002000 /* FS reparse point */
+#define XAT0_GEN 0x00004000 /* object generation number */
+#define XAT0_OFFLINE 0x00008000 /* offline */
+#define XAT0_SPARSE 0x00010000 /* sparse */
+
+#define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
+ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
+ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| XAT0_AV_MODIFIED| \
+ XAT0_AV_SCANSTAMP|XAT0_REPARSE|XATO_GEN|XAT0_OFFLINE|XAT0_SPARSE)
+
+/* Support for XAT_* optional attributes */
+#define XVA_MASK 0xffffffff /* Used to mask off 32 bits */
+#define XVA_SHFT 32 /* Used to shift index */
+
+/*
+ * Used to pry out the index and attribute bits from the XAT_* attributes
+ * defined below. Note that we're masking things down to 32 bits then
+ * casting to uint32_t.
+ */
+#define XVA_INDEX(attr) ((uint32_t)(((attr) >> XVA_SHFT) & XVA_MASK))
+#define XVA_ATTRBIT(attr) ((uint32_t)((attr) & XVA_MASK))
+
+/*
+ * The following defines present a "flat namespace" so that consumers don't
+ * need to keep track of which element belongs to which bitmap entry.
+ *
+ * NOTE THAT THESE MUST NEVER BE OR-ed TOGETHER
+ */
+#define XAT_CREATETIME ((XAT0_INDEX << XVA_SHFT) | XAT0_CREATETIME)
+#define XAT_ARCHIVE ((XAT0_INDEX << XVA_SHFT) | XAT0_ARCHIVE)
+#define XAT_SYSTEM ((XAT0_INDEX << XVA_SHFT) | XAT0_SYSTEM)
+#define XAT_READONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_READONLY)
+#define XAT_HIDDEN ((XAT0_INDEX << XVA_SHFT) | XAT0_HIDDEN)
+#define XAT_NOUNLINK ((XAT0_INDEX << XVA_SHFT) | XAT0_NOUNLINK)
+#define XAT_IMMUTABLE ((XAT0_INDEX << XVA_SHFT) | XAT0_IMMUTABLE)
+#define XAT_APPENDONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_APPENDONLY)
+#define XAT_NODUMP ((XAT0_INDEX << XVA_SHFT) | XAT0_NODUMP)
+#define XAT_OPAQUE ((XAT0_INDEX << XVA_SHFT) | XAT0_OPAQUE)
+#define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
+#define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
+#define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+#define XAT_REPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
+#define XAT_GEN ((XAT0_INDEX << XVA_SHFT) | XAT0_GEN)
+#define XAT_OFFLINE ((XAT0_INDEX << XVA_SHFT) | XAT0_OFFLINE)
+#define XAT_SPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_SPARSE)
+
+/*
+ * The returned attribute map array (xva_rtnattrmap[]) is located past the
+ * requested attribute map array (xva_reqattrmap[]). Its location changes
+ * when the array sizes change. We use a separate pointer in a known location
+ * (xva_rtnattrmapp) to hold the location of xva_rtnattrmap[]. This is
+ * set in xva_init()
+ */
+#define XVA_RTNATTRMAP(xvap) ((xvap)->xva_rtnattrmapp)
+
+/*
+ * XVA_SET_REQ() sets an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_SET_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+/*
+ * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_CLR_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr)
+
+/*
+ * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap
+ * of returned attributes (xva_rtnattrmap[]).
+ */
+#define XVA_SET_RTN(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+
+/*
+ * XVA_ISSET_REQ() checks the requested attribute bitmap (xva_reqattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_REQ(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((xvap)->xva_reqattrmap[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * XVA_ISSET_RTN() checks the returned attribute bitmap (xva_rtnattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_RTN(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * Modes. Some values same as S_xxx entries from stat.h for convenience.
+ */
+#define VSUID 04000 /* set user id on execution */
+#define VSGID 02000 /* set group id on execution */
+#define VSVTX 01000 /* save swapped text even after use */
+
+/*
+ * Permissions.
+ */
+#define VREAD 00400
+#define VWRITE 00200
+#define VEXEC 00100
+
+#define MODEMASK 07777 /* mode bits plus permission bits */
+#define PERMMASK 00777 /* permission bits */
+
+/*
+ * VOP_ACCESS flags
+ */
+#define V_ACE_MASK 0x1 /* mask represents NFSv4 ACE permissions */
+#define V_APPEND 0x2 /* want to do append only check */
+
+/*
+ * Check whether mandatory file locking is enabled.
+ */
+
+#define MANDMODE(mode) (((mode) & (VSGID|(VEXEC>>3))) == VSGID)
+#define MANDLOCK(vp, mode) ((vp)->v_type == VREG && MANDMODE(mode))
+
+/*
+ * Flags for vnode operations.
+ */
+enum rm { RMFILE, RMDIRECTORY }; /* rm or rmdir (remove) */
+enum symfollow { NO_FOLLOW, FOLLOW }; /* follow symlinks (or not) */
+enum vcexcl { NONEXCL, EXCL }; /* (non)excl create */
+enum create { CRCREAT, CRMKNOD, CRMKDIR }; /* reason for create */
+
+typedef enum rm rm_t;
+typedef enum symfollow symfollow_t;
+typedef enum vcexcl vcexcl_t;
+typedef enum create create_t;
+
+/* Vnode Events - Used by VOP_VNEVENT */
+typedef enum vnevent {
+ VE_SUPPORT = 0, /* Query */
+ VE_RENAME_SRC = 1, /* Rename, with vnode as source */
+ VE_RENAME_DEST = 2, /* Rename, with vnode as target/destination */
+ VE_REMOVE = 3, /* Remove of vnode's name */
+ VE_RMDIR = 4, /* Remove of directory vnode's name */
+ VE_CREATE = 5, /* Create with vnode's name which exists */
+ VE_LINK = 6, /* Link with vnode's name as source */
+ VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
+ VE_MOUNTEDOVER = 8, /* File or Filesystem got mounted over vnode */
+ VE_TRUNCATE = 9 /* Truncate */
+} vnevent_t;
+
+/*
+ * Values for checking vnode open and map counts
+ */
+enum v_mode { V_READ, V_WRITE, V_RDORWR, V_RDANDWR };
+
+typedef enum v_mode v_mode_t;
+
+#define V_TRUE 1
+#define V_FALSE 0
+
+/*
+ * Structure used on VOP_GETSECATTR and VOP_SETSECATTR operations
+ */
+
+typedef struct vsecattr {
+ uint_t vsa_mask; /* See below */
+ int vsa_aclcnt; /* ACL entry count */
+ void *vsa_aclentp; /* pointer to ACL entries */
+ int vsa_dfaclcnt; /* default ACL entry count */
+ void *vsa_dfaclentp; /* pointer to default ACL entries */
+ size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
+ uint_t vsa_aclflags; /* ACE ACL flags */
+} vsecattr_t;
+
+/* vsa_mask values */
+#define VSA_ACL 0x0001
+#define VSA_ACLCNT 0x0002
+#define VSA_DFACL 0x0004
+#define VSA_DFACLCNT 0x0008
+#define VSA_ACE 0x0010
+#define VSA_ACECNT 0x0020
+#define VSA_ACE_ALLTYPES 0x0040
+#define VSA_ACE_ACLFLAGS 0x0080 /* get/set ACE ACL flags */
+
+/*
+ * Structure used by various vnode operations to determine
+ * the context (pid, host, identity) of a caller.
+ *
+ * The cc_caller_id is used to identify one or more callers who invoke
+ * operations, possibly on behalf of others. For example, the NFS
+ * server could have it's own cc_caller_id which can be detected by
+ * vnode/vfs operations or (FEM) monitors on those operations. New
+ * caller IDs are generated by fs_new_caller_id().
+ */
+typedef struct caller_context {
+ pid_t cc_pid; /* Process ID of the caller */
+ int cc_sysid; /* System ID, used for remote calls */
+ u_longlong_t cc_caller_id; /* Identifier for (set of) caller(s) */
+ ulong_t cc_flags;
+} caller_context_t;
+
+/*
+ * Flags for caller context. The caller sets CC_DONTBLOCK if it does not
+ * want to block inside of a FEM monitor. The monitor will set CC_WOULDBLOCK
+ * and return EAGAIN if the operation would have blocked.
+ */
+#define CC_WOULDBLOCK 0x01
+#define CC_DONTBLOCK 0x02
+
+/*
+ * Structure tags for function prototypes, defined elsewhere.
+ */
+struct pathname;
+struct fid;
+struct flock64;
+struct flk_callback;
+struct shrlock;
+struct page;
+struct seg;
+struct as;
+struct pollhead;
+struct taskq;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VNODE_OPS defines all the vnode operations. It is used to define
+ * the vnodeops structure (below) and the fs_func_p union (vfs_opreg.h).
+ */
+#define VNODE_OPS \
+ int (*vop_open)(vnode_t **, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_close)(vnode_t *, int, int, offset_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_read)(vnode_t *, uio_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_write)(vnode_t *, uio_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_ioctl)(vnode_t *, int, intptr_t, int, cred_t *, \
+ int *, caller_context_t *); \
+ int (*vop_setfl)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_getattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_setattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_access)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_lookup)(vnode_t *, char *, vnode_t **, \
+ struct pathname *, \
+ int, vnode_t *, cred_t *, \
+ caller_context_t *, int *, \
+ struct pathname *); \
+ int (*vop_create)(vnode_t *, char *, vattr_t *, vcexcl_t, \
+ int, vnode_t **, cred_t *, int, \
+ caller_context_t *, vsecattr_t *); \
+ int (*vop_remove)(vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_link)(vnode_t *, vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_rename)(vnode_t *, char *, vnode_t *, char *, \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_mkdir)(vnode_t *, char *, vattr_t *, vnode_t **, \
+ cred_t *, caller_context_t *, int, \
+ vsecattr_t *); \
+ int (*vop_rmdir)(vnode_t *, char *, vnode_t *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_readdir)(vnode_t *, uio_t *, cred_t *, int *, \
+ caller_context_t *, int); \
+ int (*vop_symlink)(vnode_t *, char *, vattr_t *, char *, \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_readlink)(vnode_t *, uio_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fsync)(vnode_t *, int, cred_t *, \
+ caller_context_t *); \
+ void (*vop_inactive)(vnode_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fid)(vnode_t *, struct fid *, \
+ caller_context_t *); \
+ int (*vop_rwlock)(vnode_t *, int, caller_context_t *); \
+ void (*vop_rwunlock)(vnode_t *, int, caller_context_t *); \
+ int (*vop_seek)(vnode_t *, offset_t, offset_t *, \
+ caller_context_t *); \
+ int (*vop_cmp)(vnode_t *, vnode_t *, caller_context_t *); \
+ int (*vop_frlock)(vnode_t *, int, struct flock64 *, \
+ int, offset_t, \
+ struct flk_callback *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_space)(vnode_t *, int, struct flock64 *, \
+ int, offset_t, \
+ cred_t *, caller_context_t *); \
+ int (*vop_realvp)(vnode_t *, vnode_t **, \
+ caller_context_t *); \
+ int (*vop_getpage)(vnode_t *, offset_t, size_t, uint_t *, \
+ struct page **, size_t, struct seg *, \
+ caddr_t, enum seg_rw, cred_t *, \
+ caller_context_t *); \
+ int (*vop_putpage)(vnode_t *, offset_t, size_t, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_map)(vnode_t *, offset_t, struct as *, \
+ caddr_t *, size_t, \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_addmap)(vnode_t *, offset_t, struct as *, \
+ caddr_t, size_t, \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_delmap)(vnode_t *, offset_t, struct as *, \
+ caddr_t, size_t, \
+ uint_t, uint_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_poll)(vnode_t *, short, int, short *, \
+ struct pollhead **, \
+ caller_context_t *); \
+ int (*vop_dump)(vnode_t *, caddr_t, offset_t, offset_t, \
+ caller_context_t *); \
+ int (*vop_pathconf)(vnode_t *, int, ulong_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_pageio)(vnode_t *, struct page *, \
+ u_offset_t, size_t, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_dumpctl)(vnode_t *, int, offset_t *, \
+ caller_context_t *); \
+ void (*vop_dispose)(vnode_t *, struct page *, \
+ int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_setsecattr)(vnode_t *, vsecattr_t *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_getsecattr)(vnode_t *, vsecattr_t *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_shrlock)(vnode_t *, int, struct shrlock *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, \
+ char *, caller_context_t *); \
+ int (*vop_reqzcbuf)(vnode_t *, enum uio_rw, xuio_t *, \
+ cred_t *, caller_context_t *); \
+ int (*vop_retzcbuf)(vnode_t *, xuio_t *, cred_t *, \
+ caller_context_t *)
+ /* NB: No ";" */
+
+/*
+ * Operations on vnodes. Note: File systems must never operate directly
+ * on a 'vnodeops' structure -- it WILL change in future releases! They
+ * must use vn_make_ops() to create the structure.
+ */
+typedef struct vnodeops {
+ const char *vnop_name;
+ VNODE_OPS; /* Signatures of all vnode operations (vops) */
+} vnodeops_t;
+
+typedef int (*fs_generic_func_p) (); /* Generic vop/vfsop/femop/fsemop ptr */
+
+extern int fop_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int fop_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+extern int fop_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
+extern int fop_write(vnode_t *, uio_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+extern int fop_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_setattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
+ int, vnode_t *, cred_t *, caller_context_t *,
+ int *, struct pathname *);
+extern int fop_create(vnode_t *, char *, vattr_t *, vcexcl_t, int,
+ vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+extern int fop_remove(vnode_t *vp, char *, cred_t *, caller_context_t *,
+ int);
+extern int fop_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
+ caller_context_t *, int, vsecattr_t *);
+extern int fop_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+extern int fop_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
+extern int fop_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+extern void fop_inactive(vnode_t *, cred_t *, caller_context_t *);
+extern int fop_fid(vnode_t *, struct fid *, caller_context_t *);
+extern int fop_rwlock(vnode_t *, int, caller_context_t *);
+extern void fop_rwunlock(vnode_t *, int, caller_context_t *);
+extern int fop_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+extern int fop_cmp(vnode_t *, vnode_t *, caller_context_t *);
+extern int fop_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
+ struct flk_callback *, cred_t *,
+ caller_context_t *);
+extern int fop_space(vnode_t *, int, struct flock64 *, int, offset_t,
+ cred_t *, caller_context_t *);
+extern int fop_realvp(vnode_t *, vnode_t **, caller_context_t *);
+extern int fop_getpage(vnode_t *, offset_t, size_t, uint_t *,
+ struct page **, size_t, struct seg *,
+ caddr_t, enum seg_rw, cred_t *,
+ caller_context_t *);
+extern int fop_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+extern int fop_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *cr,
+ caller_context_t *);
+extern int fop_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+extern int fop_dump(vnode_t *, caddr_t, offset_t, offset_t,
+ caller_context_t *);
+extern int fop_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+extern int fop_pageio(vnode_t *, struct page *, u_offset_t, size_t, int,
+ cred_t *, caller_context_t *);
+extern int fop_dumpctl(vnode_t *, int, offset_t *, caller_context_t *);
+extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *,
+ caller_context_t *);
+extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
+extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *,
+ caller_context_t *);
+extern int fop_reqzcbuf(vnode_t *, enum uio_rw, xuio_t *, cred_t *,
+ caller_context_t *);
+extern int fop_retzcbuf(vnode_t *, xuio_t *, cred_t *, caller_context_t *);
+
+#endif /* _KERNEL */
+
+#define VOP_OPEN(vpp, mode, cr, ct) \
+ fop_open(vpp, mode, cr, ct)
+#define VOP_CLOSE(vp, f, c, o, cr, ct) \
+ fop_close(vp, f, c, o, cr, ct)
+#define VOP_READ(vp, uiop, iof, cr, ct) \
+ fop_read(vp, uiop, iof, cr, ct)
+#define VOP_WRITE(vp, uiop, iof, cr, ct) \
+ fop_write(vp, uiop, iof, cr, ct)
+#define VOP_IOCTL(vp, cmd, a, f, cr, rvp, ct) \
+ fop_ioctl(vp, cmd, a, f, cr, rvp, ct)
+#define VOP_SETFL(vp, f, a, cr, ct) \
+ fop_setfl(vp, f, a, cr, ct)
+#define VOP_GETATTR(vp, vap, f, cr, ct) \
+ fop_getattr(vp, vap, f, cr, ct)
+#define VOP_SETATTR(vp, vap, f, cr, ct) \
+ fop_setattr(vp, vap, f, cr, ct)
+#define VOP_ACCESS(vp, mode, f, cr, ct) \
+ fop_access(vp, mode, f, cr, ct)
+#define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp) \
+ fop_lookup(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp)
+#define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap) \
+ fop_create(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap)
+#define VOP_REMOVE(dvp, p, cr, ct, f) \
+ fop_remove(dvp, p, cr, ct, f)
+#define VOP_LINK(tdvp, fvp, p, cr, ct, f) \
+ fop_link(tdvp, fvp, p, cr, ct, f)
+#define VOP_RENAME(fvp, fnm, tdvp, tnm, cr, ct, f) \
+ fop_rename(fvp, fnm, tdvp, tnm, cr, ct, f)
+#define VOP_MKDIR(dp, p, vap, vpp, cr, ct, f, vsap) \
+ fop_mkdir(dp, p, vap, vpp, cr, ct, f, vsap)
+#define VOP_RMDIR(dp, p, cdir, cr, ct, f) \
+ fop_rmdir(dp, p, cdir, cr, ct, f)
+#define VOP_READDIR(vp, uiop, cr, eofp, ct, f) \
+ fop_readdir(vp, uiop, cr, eofp, ct, f)
+#define VOP_SYMLINK(dvp, lnm, vap, tnm, cr, ct, f) \
+ fop_symlink(dvp, lnm, vap, tnm, cr, ct, f)
+#define VOP_READLINK(vp, uiop, cr, ct) \
+ fop_readlink(vp, uiop, cr, ct)
+#define VOP_FSYNC(vp, syncflag, cr, ct) \
+ fop_fsync(vp, syncflag, cr, ct)
+#define VOP_INACTIVE(vp, cr, ct) \
+ fop_inactive(vp, cr, ct)
+#define VOP_FID(vp, fidp, ct) \
+ fop_fid(vp, fidp, ct)
+#define VOP_RWLOCK(vp, w, ct) \
+ fop_rwlock(vp, w, ct)
+#define VOP_RWUNLOCK(vp, w, ct) \
+ fop_rwunlock(vp, w, ct)
+#define VOP_SEEK(vp, ooff, noffp, ct) \
+ fop_seek(vp, ooff, noffp, ct)
+#define VOP_CMP(vp1, vp2, ct) \
+ fop_cmp(vp1, vp2, ct)
+#define VOP_FRLOCK(vp, cmd, a, f, o, cb, cr, ct) \
+ fop_frlock(vp, cmd, a, f, o, cb, cr, ct)
+#define VOP_SPACE(vp, cmd, a, f, o, cr, ct) \
+ fop_space(vp, cmd, a, f, o, cr, ct)
+#define VOP_REALVP(vp1, vp2, ct) \
+ fop_realvp(vp1, vp2, ct)
+#define VOP_GETPAGE(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct) \
+ fop_getpage(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct)
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) \
+ fop_putpage(vp, of, sz, fl, cr, ct)
+#define VOP_MAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_map(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_ADDMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_addmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_DELMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_delmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_POLL(vp, events, anyyet, reventsp, phpp, ct) \
+ fop_poll(vp, events, anyyet, reventsp, phpp, ct)
+#define VOP_DUMP(vp, addr, bn, count, ct) \
+ fop_dump(vp, addr, bn, count, ct)
+#define VOP_PATHCONF(vp, cmd, valp, cr, ct) \
+ fop_pathconf(vp, cmd, valp, cr, ct)
+#define VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct) \
+ fop_pageio(vp, pp, io_off, io_len, flags, cr, ct)
+#define VOP_DUMPCTL(vp, action, blkp, ct) \
+ fop_dumpctl(vp, action, blkp, ct)
+#define VOP_DISPOSE(vp, pp, flag, dn, cr, ct) \
+ fop_dispose(vp, pp, flag, dn, cr, ct)
+#define VOP_GETSECATTR(vp, vsap, f, cr, ct) \
+ fop_getsecattr(vp, vsap, f, cr, ct)
+#define VOP_SETSECATTR(vp, vsap, f, cr, ct) \
+ fop_setsecattr(vp, vsap, f, cr, ct)
+#define VOP_SHRLOCK(vp, cmd, shr, f, cr, ct) \
+ fop_shrlock(vp, cmd, shr, f, cr, ct)
+#define VOP_VNEVENT(vp, vnevent, dvp, fnm, ct) \
+ fop_vnevent(vp, vnevent, dvp, fnm, ct)
+#define VOP_REQZCBUF(vp, rwflag, xuiop, cr, ct) \
+ fop_reqzcbuf(vp, rwflag, xuiop, cr, ct)
+#define VOP_RETZCBUF(vp, xuiop, cr, ct) \
+ fop_retzcbuf(vp, xuiop, cr, ct)
+
+#define VOPNAME_OPEN "open"
+#define VOPNAME_CLOSE "close"
+#define VOPNAME_READ "read"
+#define VOPNAME_WRITE "write"
+#define VOPNAME_IOCTL "ioctl"
+#define VOPNAME_SETFL "setfl"
+#define VOPNAME_GETATTR "getattr"
+#define VOPNAME_SETATTR "setattr"
+#define VOPNAME_ACCESS "access"
+#define VOPNAME_LOOKUP "lookup"
+#define VOPNAME_CREATE "create"
+#define VOPNAME_REMOVE "remove"
+#define VOPNAME_LINK "link"
+#define VOPNAME_RENAME "rename"
+#define VOPNAME_MKDIR "mkdir"
+#define VOPNAME_RMDIR "rmdir"
+#define VOPNAME_READDIR "readdir"
+#define VOPNAME_SYMLINK "symlink"
+#define VOPNAME_READLINK "readlink"
+#define VOPNAME_FSYNC "fsync"
+#define VOPNAME_INACTIVE "inactive"
+#define VOPNAME_FID "fid"
+#define VOPNAME_RWLOCK "rwlock"
+#define VOPNAME_RWUNLOCK "rwunlock"
+#define VOPNAME_SEEK "seek"
+#define VOPNAME_CMP "cmp"
+#define VOPNAME_FRLOCK "frlock"
+#define VOPNAME_SPACE "space"
+#define VOPNAME_REALVP "realvp"
+#define VOPNAME_GETPAGE "getpage"
+#define VOPNAME_PUTPAGE "putpage"
+#define VOPNAME_MAP "map"
+#define VOPNAME_ADDMAP "addmap"
+#define VOPNAME_DELMAP "delmap"
+#define VOPNAME_POLL "poll"
+#define VOPNAME_DUMP "dump"
+#define VOPNAME_PATHCONF "pathconf"
+#define VOPNAME_PAGEIO "pageio"
+#define VOPNAME_DUMPCTL "dumpctl"
+#define VOPNAME_DISPOSE "dispose"
+#define VOPNAME_GETSECATTR "getsecattr"
+#define VOPNAME_SETSECATTR "setsecattr"
+#define VOPNAME_SHRLOCK "shrlock"
+#define VOPNAME_VNEVENT "vnevent"
+#define VOPNAME_REQZCBUF "reqzcbuf"
+#define VOPNAME_RETZCBUF "retzcbuf"
+
+/*
+ * Flags for VOP_LOOKUP
+ *
+ * Defined in file.h, but also possible, FIGNORECASE and FSEARCH
+ *
+ */
+#define LOOKUP_DIR 0x01 /* want parent dir vp */
+#define LOOKUP_XATTR 0x02 /* lookup up extended attr dir */
+#define CREATE_XATTR_DIR 0x04 /* Create extended attr dir */
+#define LOOKUP_HAVE_SYSATTR_DIR 0x08 /* Already created virtual GFS dir */
+
+/*
+ * Flags for VOP_READDIR
+ */
+#define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */
+#define V_RDDIR_ACCFILTER 0x02 /* filter out inaccessible dirents */
+
+/*
+ * Flags for VOP_RWLOCK/VOP_RWUNLOCK
+ * VOP_RWLOCK will return the flag that was actually set, or -1 if none.
+ */
+#define V_WRITELOCK_TRUE (1) /* Request write-lock on the vnode */
+#define V_WRITELOCK_FALSE (0) /* Request read-lock on the vnode */
+
+/*
+ * Flags for VOP_DUMPCTL
+ */
+#define DUMP_ALLOC 0
+#define DUMP_FREE 1
+#define DUMP_SCAN 2
+
+/*
+ * Public vnode manipulation functions.
+ */
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+vnode_t *vn_alloc(int);
+void vn_reinit(vnode_t *);
+void vn_recycle(vnode_t *);
+void vn_free(vnode_t *);
+
+int vn_is_readonly(vnode_t *);
+int vn_is_opened(vnode_t *, v_mode_t);
+int vn_is_mapped(vnode_t *, v_mode_t);
+int vn_has_other_opens(vnode_t *, v_mode_t);
+void vn_open_upgrade(vnode_t *, int);
+void vn_open_downgrade(vnode_t *, int);
+
+int vn_can_change_zones(vnode_t *vp);
+
+int vn_has_flocks(vnode_t *);
+int vn_has_mandatory_locks(vnode_t *, int);
+int vn_has_cached_data(vnode_t *);
+
+void vn_setops(vnode_t *, vnodeops_t *);
+vnodeops_t *vn_getops(vnode_t *);
+int vn_matchops(vnode_t *, vnodeops_t *);
+int vn_matchopval(vnode_t *, char *, fs_generic_func_p);
+int vn_ismntpt(vnode_t *);
+
+struct vfs *vn_mountedvfs(vnode_t *);
+
+int vn_in_dnlc(vnode_t *);
+
+void vn_create_cache(void);
+void vn_destroy_cache(void);
+
+void vn_freevnodeops(vnodeops_t *);
+
+int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy, mode_t umask);
+int vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy,
+ mode_t umask, struct vnode *startvp, int fd);
+int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask);
+int vn_createat(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask, struct vnode *startvp);
+int vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, ssize_t len,
+ offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit,
+ cred_t *cr, ssize_t *residp);
+
+void vn_hold(struct vnode *vp);
+void vn_rele(struct vnode *vp);
+void vn_rele_async(struct vnode *vp, struct taskq *taskq);
+void vn_rele_dnlc(struct vnode *vp);
+void vn_rele_stream(struct vnode *vp);
+int vn_link(char *from, char *to, enum uio_seg seg);
+int vn_linkat(vnode_t *fstartvp, char *from, enum symfollow follow,
+ vnode_t *tstartvp, char *to, enum uio_seg seg);
+int vn_rename(char *from, char *to, enum uio_seg seg);
+int vn_renameat(vnode_t *fdvp, char *fname, vnode_t *tdvp, char *tname,
+ enum uio_seg seg);
+int vn_remove(char *fnamep, enum uio_seg seg, enum rm dirflag);
+int vn_removeat(vnode_t *startvp, char *fnamep, enum uio_seg seg,
+ enum rm dirflag);
+int vn_compare(vnode_t *vp1, vnode_t *vp2);
+int vn_vfswlock(struct vnode *vp);
+int vn_vfswlock_wait(struct vnode *vp);
+int vn_vfsrlock(struct vnode *vp);
+int vn_vfsrlock_wait(struct vnode *vp);
+void vn_vfsunlock(struct vnode *vp);
+int vn_vfswlock_held(struct vnode *vp);
+vnode_t *specvp(struct vnode *vp, dev_t dev, vtype_t type, struct cred *cr);
+vnode_t *makespecvp(dev_t dev, vtype_t type);
+
+#if defined(_KERNEL)
+vn_vfslocks_entry_t *vn_vfslocks_getlock(void *);
+void vn_vfslocks_rele(vn_vfslocks_entry_t *);
+#endif
+
+boolean_t vn_is_reparse(vnode_t *, cred_t *, caller_context_t *);
+
+void vn_copypath(struct vnode *src, struct vnode *dst);
+void vn_setpath_str(struct vnode *vp, const char *str, size_t len);
+void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
+ const char *path, size_t plen);
+void vn_renamepath(vnode_t *dvp, vnode_t *vp, const char *nm, size_t len);
+
+/* Vnode event notification */
+void vnevent_rename_src(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rename_dest(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_remove(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rmdir(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_create(vnode_t *, caller_context_t *);
+void vnevent_link(vnode_t *, caller_context_t *);
+void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
+void vnevent_mountedover(vnode_t *, caller_context_t *);
+void vnevent_truncate(vnode_t *, caller_context_t *);
+int vnevent_support(vnode_t *, caller_context_t *);
+
+/* Vnode specific data */
+void vsd_create(uint_t *, void (*)(void *));
+void vsd_destroy(uint_t *);
+void *vsd_get(vnode_t *, uint_t);
+int vsd_set(vnode_t *, uint_t, void *);
+void vsd_free(vnode_t *);
+
+/*
+ * Extensible vnode attribute (xva) routines:
+ * xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
+ * xva_getxoptattr() returns a ponter to the xoptattr_t section of xvattr_t
+ */
+void xva_init(xvattr_t *);
+xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
+
+void xattr_init(void); /* Initialize vnodeops for xattrs */
+
+/* GFS tunnel for xattrs */
+int xattr_dir_lookup(vnode_t *, vnode_t **, int, cred_t *);
+
+/* Reparse Point */
+void reparse_point_init(void);
+
+/* Context identification */
+u_longlong_t fs_new_caller_id();
+
+int vn_vmpss_usepageio(vnode_t *);
+
+/* Empty v_path placeholder */
+extern char *vn_vpath_empty;
+
+/*
+ * Needed for use of IS_VMODSORT() in kernel.
+ */
+extern uint_t pvn_vmodsort_supported;
+
+#define VN_HOLD(vp) { \
+ vn_hold(vp); \
+}
+
+#define VN_RELE(vp) { \
+ vn_rele(vp); \
+}
+
+#define VN_RELE_ASYNC(vp, taskq) { \
+ vn_rele_async(vp, taskq); \
+}
+
+#define VN_RELE_LOCKED(vp) { \
+ (vp)->v_count--; \
+}
+
+#define VN_SET_VFS_TYPE_DEV(vp, vfsp, type, dev) { \
+ (vp)->v_vfsp = (vfsp); \
+ (vp)->v_type = (type); \
+ (vp)->v_rdev = (dev); \
+}
+
+/*
+ * Compare two vnodes for equality. In general this macro should be used
+ * in preference to calling VOP_CMP directly.
+ */
+#if defined(_FAKE_KERNEL)
+#define VN_CMP(VP1, VP2) \
+ (((VP1) == (VP2)) ? 1 : VOP_CMP(VP1, VP2, NULL))
+#else
+#define VN_CMP(VP1, VP2) ((VP1) == (VP2) ? 1 : \
+ ((VP1) && (VP2) && (vn_getops(VP1) == vn_getops(VP2)) ? \
+ VOP_CMP(VP1, VP2, NULL) : 0))
+#endif
+
+/*
+ * Some well-known global vnodes used by the VM system to name pages.
+ */
+extern struct vnode kvps[];
+
+typedef enum {
+ KV_KVP, /* vnode for all segkmem pages */
+ KV_ZVP, /* vnode for all ZFS pages */
+#if defined(__sparc)
+ KV_MPVP, /* vnode for all page_t meta-pages */
+ KV_PROMVP, /* vnode for all PROM pages */
+#endif /* __sparc */
+ KV_MAX /* total number of vnodes in kvps[] */
+} kvps_index_t;
+
+#define VN_ISKAS(vp) ((vp) >= &kvps[0] && (vp) < &kvps[KV_MAX])
+
+#endif /* _KERNEL */
+
+/*
+ * Flags to VOP_SETATTR/VOP_GETATTR.
+ */
+#define ATTR_UTIME 0x01 /* non-default utime(2) request */
+#define ATTR_EXEC 0x02 /* invocation from exec(2) */
+#define ATTR_COMM 0x04 /* yield common vp attributes */
+#define ATTR_HINT 0x08 /* information returned will be `hint' */
+#define ATTR_REAL 0x10 /* yield attributes of the real vp */
+#define ATTR_NOACLCHECK 0x20 /* Don't check ACL when checking permissions */
+#define ATTR_TRIGGER 0x40 /* Mount first if vnode is a trigger mount */
+/*
+ * Generally useful macros.
+ */
+#define VBSIZE(vp) ((vp)->v_vfsp->vfs_bsize)
+
+#define VTOZONE(vp) ((vp)->v_vfsp->vfs_zone)
+
+#define NULLVP ((struct vnode *)0)
+#define NULLVPP ((struct vnode **)0)
+
+#ifdef _KERNEL
+
+/*
+ * Structure used while handling asynchronous VOP_PUTPAGE operations.
+ */
+struct async_reqs {
+ struct async_reqs *a_next; /* pointer to next arg struct */
+ struct vnode *a_vp; /* vnode pointer */
+ u_offset_t a_off; /* offset in file */
+ uint_t a_len; /* size of i/o request */
+ int a_flags; /* flags to indicate operation type */
+ struct cred *a_cred; /* cred pointer */
+ ushort_t a_prealloced; /* set if struct is pre-allocated */
+};
+
+/*
+ * VN_DISPOSE() -- given a page pointer, safely invoke VOP_DISPOSE().
+ * Note that there is no guarantee that the page passed in will be
+ * freed. If that is required, then a check after calling VN_DISPOSE would
+ * be necessary to ensure the page was freed.
+ */
+#define VN_DISPOSE(pp, flag, dn, cr) { \
+ if ((pp)->p_vnode != NULL && !VN_ISKAS((pp)->p_vnode)) \
+ VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr), NULL); \
+ else if ((flag) == B_FREE) \
+ page_free((pp), (dn)); \
+ else \
+ page_destroy((pp), (dn)); \
+ }
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VNODE_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/i386/Makefile b/usr/src/lib/smbclnt/libfknsmb/i386/Makefile
new file mode 100644
index 0000000000..40b7e3bf5d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile b/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile
new file mode 100644
index 0000000000..40b7e3bf5d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile b/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile
new file mode 100644
index 0000000000..de1ec045d8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile b/usr/src/lib/smbclnt/libfksmbfs/Makefile
new file mode 100644
index 0000000000..ee4ab9faf7
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.smbclnt
diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile.com b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
new file mode 100644
index 0000000000..abc12a9464
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
@@ -0,0 +1,139 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+#
+
+LIBRARY = libfksmbfs.a
+VERS = .1
+
+OBJS_LOCAL = \
+ fksmbfs_rwlock.o \
+ fake_fssub.o \
+ fake_getdents.o \
+ fake_lookup.o \
+ fake_misc.o \
+ fake_modconf.o \
+ fake_nbmlock.o \
+ fake_open.o \
+ fake_rename.o \
+ fake_rw.o \
+ fake_stat.o \
+ fake_unlink.o \
+ fake_vfs.o \
+ fake_vnode.o \
+ fake_zone.o
+
+# See also: $SRC/uts/common/Makefile.files
+# NB: Intentionally ommitted, compared w/ the above:
+# smbfs_rwlock.o
+#
+OBJS_FS_SMBFS = \
+ smbfs_vfsops.o \
+ smbfs_vnops.o \
+ smbfs_client.o \
+ smbfs_node.o \
+ smbfs_smb.o \
+ smbfs_smb1.o \
+ smbfs_smb2.o \
+ smbfs_subr.o \
+ smbfs_subr2.o \
+ smbfs_acl.o \
+ smbfs_xattr.o
+
+OBJS_CMN_SMBFS = \
+ smbfs_ntacl.o
+
+OBJS_MISC = \
+ acl_common.o \
+ pathname.o \
+ refstr.o
+
+OBJECTS = \
+ $(OBJS_LOCAL) \
+ $(OBJS_FS_SMBFS) \
+ $(OBJS_CMN_SMBFS) \
+ $(OBJS_MISC)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+CPPFLAGS.first += -I../../../libfakekernel/common
+CPPFLAGS.first += -I../../libfknsmb/common
+CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+INCS += -I$(SRC)/common/smbclnt
+INCS += -I$(SRC)/common
+
+CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CERRWARN += -_gcc=-Wno-switch
+CERRWARN += -_gcc=-Wno-parentheses
+
+LDLIBS += $(MACH_LDLIBS)
+LDLIBS += -lfknsmb -lfakekernel -lidmap -lcmdutils -lavl -lc
+
+FS_SMBFS_DIR=$(SRC)/uts/common/fs/smbclnt/smbfs
+CMN_SMBFS_DIR=$(SRC)/common/smbclnt
+SRCS= $(OBJS_LOCAL:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_FS_SMBFS:%.o=$(FS_SMBFS_DIR)/%.c) \
+ $(OBJS_CMN_SMBFS:%.o=$(CMN_SMBFS_DIR)/%.c)
+
+all:
+
+pics/%.o: $(FS_SMBFS_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# pathname.o
+pics/%.o: $(SRC)/uts/common/fs/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# refstr.o
+pics/%.o: $(SRC)/uts/common/os/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/acl_common.o: $(SRC)/common/acl/acl_common.c
+ $(COMPILE.c) -o $@ $(SRC)/common/acl/acl_common.c
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile b/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile
new file mode 100644
index 0000000000..8b52fdf7af
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbfs/$(MACH64)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c
new file mode 100644
index 0000000000..336406f095
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c
@@ -0,0 +1,432 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Generic vnode operations.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/flock.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/cred.h>
+#include <sys/poll.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/share.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/nbmlock.h>
+#include <sys/acl.h>
+
+#include <acl/acl_common.h>
+#include <fs/fs_subr.h>
+
+/*
+ * Tunable to limit the number of retry to recover from STALE error.
+ */
+int fs_estale_retry = 5;
+
+/*
+ * The associated operation is not supported by the file system.
+ */
+int
+fs_nosys()
+{
+ return (ENOSYS);
+}
+
+/*
+ * The associated operation is invalid (on this vnode).
+ */
+int
+fs_inval()
+{
+ return (EINVAL);
+}
+
+/*
+ * The associated operation is valid only for directories.
+ */
+int
+fs_notdir()
+{
+ return (ENOTDIR);
+}
+
+/*
+ * Free the file system specific resources. For the file systems that
+ * do not support the forced unmount, it will be a nop function.
+ */
+
+/*ARGSUSED*/
+void
+fs_freevfs(vfs_t *vfsp)
+{
+}
+
+/* ARGSUSED */
+int
+fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/* ARGSUSED */
+int
+fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/* ARGSUSED */
+int
+fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp, caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+
+/*
+ * The file system has nothing to sync to disk. However, the
+ * VFS_SYNC operation must not fail.
+ */
+/* ARGSUSED */
+int
+fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_FSYNC must not fail.
+ */
+/* ARGSUSED */
+int
+fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_PUTPAGE must not fail.
+ */
+/* ARGSUSED */
+int
+fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ctp)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_IOCTL must not fail.
+ */
+/* ARGSUSED */
+int
+fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
+ int *rvalp)
+{
+ return (0);
+}
+
+/*
+ * Read/write lock/unlock. Does nothing.
+ */
+/* ARGSUSED */
+int
+fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+void
+fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+}
+
+/*
+ * Compare two vnodes.
+ */
+/*ARGSUSED2*/
+int
+fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
+{
+ return (vp1 == vp2);
+}
+
+/*
+ * No-op seek operation.
+ */
+/* ARGSUSED */
+int
+fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
+{
+ return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
+}
+
+/*
+ * File and record locking.
+ */
+/* ARGSUSED */
+int
+fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
+ flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/*
+ * Allow any flags.
+ */
+/* ARGSUSED */
+int
+fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Return the answer requested to poll() for non-device files.
+ * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
+ */
+struct pollhead fs_pollhd;
+
+/* ARGSUSED */
+int
+fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp, caller_context_t *ct)
+{
+ if (events & POLLET) {
+ return (EPERM);
+ }
+
+ *reventsp = 0;
+ if (events & POLLIN)
+ *reventsp |= POLLIN;
+ if (events & POLLRDNORM)
+ *reventsp |= POLLRDNORM;
+ if (events & POLLRDBAND)
+ *reventsp |= POLLRDBAND;
+ if (events & POLLOUT)
+ *reventsp |= POLLOUT;
+ if (events & POLLWRBAND)
+ *reventsp |= POLLWRBAND;
+ if (*reventsp == 0 && !anyyet) {
+ *phpp = &fs_pollhd;
+ }
+ return (0);
+}
+
+/*
+ * POSIX pathconf() support.
+ */
+/* ARGSUSED */
+int
+fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ /* not called */
+ return (EINVAL);
+}
+
+/*
+ * Dispose of a page.
+ */
+/* ARGSUSED */
+void
+fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
+ caller_context_t *ct)
+{
+}
+
+/* ARGSUSED */
+void
+fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
+ caller_context_t *ct)
+{
+ cmn_err(CE_PANIC, "fs_nodispose invoked");
+}
+
+/*
+ * fabricate acls for file systems that do not support acls.
+ */
+/* ARGSUSED */
+int
+fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
+{
+ struct vattr vattr;
+ int error;
+
+ vsecattr->vsa_aclcnt = 0;
+ vsecattr->vsa_aclentsz = 0;
+ vsecattr->vsa_aclentp = NULL;
+ vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
+ vsecattr->vsa_dfaclentp = NULL;
+
+ vattr.va_mask = AT_MODE | AT_UID | AT_GID;
+ if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
+ return (error);
+
+ if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
+ return (ENOSYS);
+ }
+
+ if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
+ VERIFY(0 == acl_trivial_create(vattr.va_mode,
+ (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
+ &vsecattr->vsa_aclcnt));
+ vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ }
+
+ return (error);
+}
+
+/*
+ * Common code for implementing DOS share reservations
+ */
+/* ARGSUSED */
+int
+fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/*ARGSUSED1*/
+int
+fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ ASSERT(vp != NULL);
+ return (ENOTSUP);
+}
+
+/*ARGSUSED1*/
+int
+fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ ASSERT(vp != NULL);
+ return (0);
+}
+
+// fs_acl_nontrivial
+
+/*
+ * Check whether we need a retry to recover from STALE error.
+ */
+int
+fs_need_estale_retry(int retry_count)
+{
+ if (retry_count < fs_estale_retry)
+ return (1);
+ else
+ return (0);
+}
+
+// fs_vscan...
+// reparse...
+
+/*
+ * A few things from os/flock.c
+ */
+
+/* ARGSUSED */
+void
+cleanlocks(vnode_t *vp, pid_t pid, int sysid)
+{
+}
+
+/* ARGSUSED */
+void
+cleanshares(struct vnode *vp, pid_t pid)
+{
+}
+
+/*
+ * convoff - converts the given data (start, whence) to the
+ * given whence.
+ */
+int
+convoff(struct vnode *vp, struct flock64 *lckdat, int whence, offset_t offset)
+{
+ int error;
+ struct vattr vattr;
+
+ if ((lckdat->l_whence == 2) || (whence == 2)) {
+ vattr.va_mask = AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ return (error);
+ }
+
+ switch (lckdat->l_whence) {
+ case 1:
+ lckdat->l_start += offset;
+ break;
+ case 2:
+ lckdat->l_start += vattr.va_size;
+ /* FALLTHRU */
+ case 0:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (lckdat->l_start < 0)
+ return (EINVAL);
+
+ switch (whence) {
+ case 1:
+ lckdat->l_start -= offset;
+ break;
+ case 2:
+ lckdat->l_start -= vattr.va_size;
+ /* FALLTHRU */
+ case 0:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ lckdat->l_whence = (short)whence;
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c
new file mode 100644
index 0000000000..afa4eb1c0f
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/dirent.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/mode.h>
+#include <sys/uio.h>
+#include <sys/filio.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+
+/*
+ * Returns count of dir entries, or -errno
+ */
+int
+fake_getdents(vnode_t *vp, offset_t *offp, void *buf, size_t count)
+{
+ struct uio auio;
+ struct iovec aiov;
+ register int error;
+ int sink;
+
+ if (count < sizeof (struct dirent64))
+ return (-EINVAL);
+
+ /*
+ * Don't let the user overcommit kernel resources.
+ */
+ if (count > MAXGETDENTS_SIZE)
+ count = MAXGETDENTS_SIZE;
+
+ if (vp->v_type != VDIR) {
+ return (-ENOTDIR);
+ }
+
+ aiov.iov_base = buf;
+ aiov.iov_len = count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = *offp;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_resid = count;
+ auio.uio_fmode = 0;
+ auio.uio_extflg = UIO_COPY_CACHED;
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(vp, &auio, CRED(), &sink, NULL, 0);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ if (error) {
+ return (-error);
+ }
+ count = count - auio.uio_resid;
+ *offp = auio.uio_loffset;
+
+ return (count);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c
new file mode 100644
index 0000000000..8072a91b3b
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c
@@ -0,0 +1,173 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/pathname.h>
+#include <sys/proc.h>
+#include <sys/vtrace.h>
+#include <sys/sysmacros.h>
+#include <sys/debug.h>
+#include <sys/dirent.h>
+#include <sys/zone.h>
+#include <sys/fs/snode.h>
+
+#include <libfksmbfs.h>
+
+extern vnode_t *rootdir;
+
+/*
+ * Simplified variation on lookuppnvp()
+ */
+int
+fake_lookup(vnode_t *dvp, char *path, vnode_t **vpp)
+{
+ char component[MAXNAMELEN]; /* buffer for component */
+ pathname_t pn;
+ cred_t *cr;
+ vnode_t *cvp; /* current component vp */
+ vnode_t *nvp; /* next component vp */
+ char *p;
+ int flags = 0;
+ int error, len;
+
+ bzero(&pn, sizeof (pn));
+ pn.pn_buf = path;
+ pn.pn_path = path;
+ pn.pn_pathlen = strlen(path);
+ pn.pn_bufsize = pn.pn_pathlen + 1;
+ p = path;
+
+ cr = CRED();
+ cvp = (dvp != NULL) ? dvp : rootdir;
+ VN_HOLD(cvp);
+ nvp = NULL;
+
+ while (*p != '\0') {
+ if (*p == '/') {
+ p++;
+ continue;
+ }
+
+ len = strcspn(p, "/");
+ ASSERT(len > 0);
+ if (len >= MAXNAMELEN)
+ return (EINVAL);
+ (void) strncpy(component, p, len);
+ component[len] = '\0';
+ pn.pn_path = p;
+ pn.pn_pathlen = strlen(p);
+
+ error = VOP_LOOKUP(cvp, component, &nvp, &pn, flags,
+ rootdir, cr, NULL, NULL, NULL);
+ VN_RELE(cvp);
+ if (error != 0)
+ return (error);
+
+ /* Lookup gave us a hold on nvp */
+ cvp = nvp;
+ nvp = NULL;
+ p += len;
+ }
+
+ *vpp = cvp;
+ return (0);
+}
+
+/*
+ * Lookup the directory and find the start of the
+ * last component of the given path.
+ */
+int
+fake_lookup_dir(char *path, vnode_t **vpp, char **lastcomp)
+{
+ vnode_t *dvp;
+ char *last;
+ char *tpn = NULL;
+ int tpn_sz;
+ int lc_off;
+ int error;
+
+ *vpp = NULL;
+ *lastcomp = NULL;
+
+ tpn_sz = strlen(path) + 1;
+ tpn = kmem_alloc(tpn_sz, KM_SLEEP);
+
+ /*
+ * Get a copy of the path, and zap the last /
+ */
+ bcopy(path, tpn, tpn_sz);
+ last = strrchr(tpn, '/');
+ if (last == NULL) {
+ lc_off = 0;
+ dvp = rootdir;
+ VN_HOLD(dvp);
+ error = 0;
+ } else {
+ *last++ = '\0';
+ if (*last == '\0') {
+ error = EINVAL;
+ goto out;
+ }
+ error = fake_lookup(rootdir, tpn, &dvp);
+ if (error != 0) {
+ /* dir not found */
+ goto out;
+ }
+ lc_off = last - tpn;
+ ASSERT(lc_off >= 0 && lc_off < tpn_sz);
+ }
+ *vpp = dvp;
+ *lastcomp = path + lc_off;
+
+out:
+ if (tpn != NULL)
+ kmem_free(tpn, tpn_sz);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c
new file mode 100644
index 0000000000..e5ab8973b4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+
+volatile int ncsize = 500; /* dnlc.h */
+
+static major_t devcnt = 0x280;
+static kmutex_t udevlock;
+
+/* os/subr.c */
+major_t
+getudev()
+{
+ static major_t next = 0;
+ major_t ret;
+
+ mutex_enter(&udevlock);
+ if (next == 0)
+ next = devcnt;
+ if (next <= L_MAXMAJ32 && next >= devcnt)
+ ret = next++;
+ else {
+ cmn_err(CE_WARN, "out of major numbers");
+ ret = ((major_t)-1);
+ }
+ mutex_exit(&udevlock);
+ return (ret);
+}
+
+/*
+ * Compress 'long' device number encoding to 32-bit device number
+ * encoding. If it won't fit, we return failure, but set the
+ * device number to 32-bit NODEV for the sake of our callers.
+ */
+int
+cmpldev(dev32_t *dst, dev_t dev)
+{
+#if defined(_LP64)
+ if (dev == NODEV) {
+ *dst = (dev32_t)(-1);
+ } else {
+ major_t major = dev >> L_BITSMINOR;
+ minor_t minor = dev & L_MAXMIN;
+
+ if (major > L_MAXMAJ32 || minor > L_MAXMIN32) {
+ *dst = (dev32_t)(-1);
+ return (0);
+ }
+
+ *dst = (dev32_t)((major << L_BITSMINOR32) | minor);
+ }
+#else
+ *dst = (dev32_t)dev;
+#endif
+ return (1);
+}
+
+/* os/cred.c */
+int
+groupmember(gid_t gid, const cred_t *cr)
+{
+ if (gid == 0 || gid == 1)
+ return (1);
+ return (0);
+}
+
+/* os/sig.c */
+
+/* ARGSUSED */
+void
+sigintr(k_sigset_t *smask, int intable)
+{
+}
+
+/* ARGSUSED */
+void
+sigunintr(k_sigset_t *smask)
+{
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c
new file mode 100644
index 0000000000..d5482f9cc5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c
@@ -0,0 +1,195 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+
+#if 0 // XXX
+
+#include <sys/user.h>
+#include <sys/vm.h>
+#include <sys/conf.h>
+#include <sys/class.h>
+#include <sys/systm.h>
+#include <sys/modctl.h>
+#include <sys/exec.h>
+#include <sys/exechdr.h>
+#include <sys/devops.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/hwconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/autoconf.h>
+#include <sys/disp.h>
+#include <sys/kmem.h>
+#include <sys/instance.h>
+#include <sys/modhash.h>
+#include <sys/dacf.h>
+#include <ipp/ipp.h>
+#include <sys/strsubr.h>
+#include <sys/kcpc.h>
+#include <sys/brand.h>
+#include <sys/cpc_pcbe.h>
+#include <sys/kstat.h>
+#include <sys/socketvar.h>
+#include <sys/kiconv.h>
+
+#endif // XXX
+
+#include <libfksmbfs.h>
+
+/*
+ * Install a filesystem.
+ */
+/*ARGSUSED1*/
+int
+fake_installfs(vfsdef_t *def)
+{
+ struct vfssw *vswp;
+ char *fsname = def->name;
+ int fstype; /* index into vfssw[] and vsanchor_fstype[] */
+ int allocated;
+ int err;
+
+ if (def->def_version != VFSDEF_VERSION) {
+ cmn_err(CE_WARN, "file system '%s' version mismatch", fsname);
+ return (ENXIO);
+ }
+
+ allocated = 0;
+
+ WLOCK_VFSSW();
+ if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) {
+ if ((vswp = allocate_vfssw(fsname)) == NULL) {
+ WUNLOCK_VFSSW();
+ /*
+ * See 1095689. If this message appears, then
+ * we either need to make the vfssw table bigger
+ * statically, or make it grow dynamically.
+ */
+ cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname);
+ return (ENXIO);
+ }
+ allocated = 1;
+ }
+ ASSERT(vswp != NULL);
+
+ fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */
+
+ /* Turn on everything by default *except* VSW_STATS */
+ vswp->vsw_flag = def->flags & ~(VSW_STATS);
+
+ if (def->flags & VSW_HASPROTO) {
+ vfs_mergeopttbl(&vfs_mntopts, def->optproto,
+ &vswp->vsw_optproto);
+ } else {
+ vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto);
+ }
+
+ if (def->flags & VSW_CANRWRO) {
+ /*
+ * This obviously implies VSW_CANREMOUNT.
+ */
+ vswp->vsw_flag |= VSW_CANREMOUNT;
+ }
+
+ /* vopstats ... */
+
+ if (def->init == NULL)
+ err = EFAULT;
+ else
+ err = (*(def->init))(fstype, fsname);
+
+ if (err != 0) {
+ if (allocated) {
+ kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1);
+ vswp->vsw_name = "";
+ }
+ vswp->vsw_flag = 0;
+ vswp->vsw_init = NULL;
+ }
+
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+
+ /* ... vopstats */
+
+ return (err);
+}
+
+int fake_removefs_allowed = 1;
+
+/*
+ * Remove a filesystem
+ */
+int
+fake_removefs(vfsdef_t *def)
+{
+ struct vfssw *vswp;
+
+ if (fake_removefs_allowed == 0)
+ return (EBUSY);
+
+ WLOCK_VFSSW();
+ if ((vswp = vfs_getvfsswbyname(def->name)) == NULL) {
+ WUNLOCK_VFSSW();
+ cmn_err(CE_WARN, "fake_removefs: %s not in vfssw",
+ def->name);
+ return (EINVAL);
+ }
+ if (vswp->vsw_count != 1) {
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (EBUSY);
+ }
+
+ /*
+ * A mounted filesystem could still have vsw_count = 0
+ * so we must check whether anyone is actually using our ops
+ */
+ if (vfs_opsinuse(&vswp->vsw_vfsops)) {
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (EBUSY);
+ }
+
+ vfs_freeopttbl(&vswp->vsw_optproto);
+ vswp->vsw_optproto.mo_count = 0;
+
+ vswp->vsw_flag = 0;
+ vswp->vsw_init = NULL;
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c
new file mode 100644
index 0000000000..c1b5ef63e8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Utility routines and top-level conflict detection code for NBMAND
+ * locks.
+ */
+
+#include <sys/nbmlock.h>
+#include <sys/rwlock.h>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/vfs.h>
+
+/*
+ * Enter the critical region for synchronizing I/O requests with lock/share
+ * requests. "mode" specifies whether the caller intends to update
+ * lock/share state (as opposed to just query it).
+ */
+
+void
+nbl_start_crit(vnode_t *vp, krw_t mode)
+{
+ rw_enter(&vp->v_nbllock, mode);
+}
+
+/*
+ * Leave the critical region.
+ */
+
+void
+nbl_end_crit(vnode_t *vp)
+{
+ rw_exit(&vp->v_nbllock);
+}
+
+/*
+ * Return non-zero if some thread is in the critical region.
+ * Note that this is appropriate for use in ASSERT()s only.
+ */
+
+int
+nbl_in_crit(vnode_t *vp)
+{
+ return (RW_LOCK_HELD(&vp->v_nbllock));
+}
+
+/*
+ * Returns non-zero if we need to look further for an NBMAND lock or
+ * share conflict.
+ */
+int
+nbl_need_check(vnode_t *vp)
+{
+ /*
+ * Currently we only check if NBMAND locks/shares are allowed on
+ * the filesystem. An option for the future would be to have a
+ * flag on the vnode, though the locking for that can get tricky.
+ */
+ return ((vp->v_vfsp) && (vp->v_vfsp->vfs_flag & VFS_NBMAND));
+}
+
+/* No locks, so no conflicts. */
+int
+nbl_conflict(vnode_t *vp,
+ nbl_op_t op, /* attempted operation */
+ u_offset_t offset, /* ignore if not I/O */
+ ssize_t length, /* ignore if not I/O */
+ int svmand, /* System V mandatory locking */
+ caller_context_t *ct) /* caller context */
+{
+ ASSERT(nbl_in_crit(vp));
+
+ return (0);
+}
+
+/*
+ * Determine if the given file has mode bits for System V mandatory locks.
+ * If there was an error, the errno value is returned. Otherwise, zero is
+ * returned and *svp is set appropriately (non-zero for mandatory locks,
+ * zero for no mandatory locks).
+ */
+
+int
+nbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
+{
+ struct vattr va;
+ int error;
+
+ va.va_mask = AT_MODE;
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
+ if (error != 0)
+ return (error);
+
+ *svp = MANDLOCK(vp, va.va_mode);
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c
new file mode 100644
index 0000000000..169197ae03
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c
@@ -0,0 +1,340 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Portions of code from both of:
+ * syscall/open.c
+ * fs/vnode.c
+ * heavily modified for this use.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <fs/fs_subr.h>
+#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
+#include <sys/time.h>
+
+#include <libfksmbfs.h>
+
+/* close and release */
+int
+vn_close_rele(vnode_t *vp, int flag)
+{
+ int error;
+
+ error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
+ vn_rele(vp);
+
+ return (error);
+}
+
+/*
+ * Open/create a vnode.
+ * This may be callable by the kernel, the only known use
+ * of user context being that the current user credentials
+ * are used for permissions. crwhy is defined iff filemode & FCREAT.
+ */
+int
+vn_open(
+ char *pnamep,
+ enum uio_seg seg,
+ int filemode,
+ int createmode,
+ struct vnode **vpp,
+ enum create crwhy,
+ mode_t umask)
+{
+ struct vnode *vp;
+ int mode;
+ int accessflags;
+ int error;
+ int open_done = 0;
+ struct vattr vattr;
+ int estale_retry = 0;
+
+ mode = 0;
+ accessflags = 0;
+ if (filemode & FREAD)
+ mode |= VREAD;
+ if (filemode & (FWRITE|FTRUNC))
+ mode |= VWRITE;
+ if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
+ mode |= VEXEC;
+
+ if (filemode & FAPPEND)
+ accessflags |= V_APPEND;
+
+top:
+ if (filemode & FCREAT) {
+ enum vcexcl excl;
+
+ /*
+ * Wish to create a file.
+ */
+ vattr.va_type = VREG;
+ vattr.va_mode = createmode;
+ vattr.va_mask = AT_TYPE|AT_MODE;
+ if (filemode & FTRUNC) {
+ vattr.va_size = 0;
+ vattr.va_mask |= AT_SIZE;
+ }
+ if (filemode & FEXCL)
+ excl = EXCL;
+ else
+ excl = NONEXCL;
+
+ if ((error =
+ vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
+ (filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
+ return (error);
+ } else {
+ /*
+ * Wish to open a file. Just look it up.
+ * Was lookupnameat()
+ */
+ if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
+ if ((error == ESTALE) &&
+ fs_need_estale_retry(estale_retry++))
+ goto top;
+ return (error);
+ }
+
+ /*
+ * Want the XATTRDIR under it?
+ */
+ if (filemode & FXATTRDIROPEN) {
+ vnode_t *xvp = NULL;
+ error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
+ LOOKUP_XATTR, rootdir, CRED(), NULL,
+ NULL, NULL);
+ VN_RELE(vp);
+ vp = xvp;
+ /* continue with vp */
+ }
+
+ /*
+ * Can't write directories, active texts, or
+ * read-only filesystems. Can't truncate files
+ * on which mandatory locking is in effect.
+ */
+ if (filemode & (FWRITE|FTRUNC)) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+ }
+ /*
+ * Check permissions.
+ */
+ if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
+ goto out;
+ /*
+ * Require FSEARCH to return a directory.
+ * Require FEXEC to return a regular file.
+ */
+ if ((filemode & FSEARCH) && vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
+ if ((filemode & FEXEC) && vp->v_type != VREG) {
+ error = ENOEXEC;
+ goto out;
+ }
+ }
+
+ /*
+ * Do remaining checks for FNOFOLLOW and FNOLINKS.
+ */
+ if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
+ error = ELOOP;
+ goto out;
+ }
+ if (filemode & FNOLINKS) {
+ vattr.va_mask = AT_NLINK;
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
+ goto out;
+ }
+ if (vattr.va_nlink != 1) {
+ error = EMLINK;
+ goto out;
+ }
+ }
+
+ /*
+ * Opening a socket corresponding to the AF_UNIX pathname
+ * in the filesystem name space is not supported...
+ */
+ if (vp->v_type == VSOCK) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
+ /*
+ * Do opening protocol.
+ */
+ error = VOP_OPEN(&vp, filemode, CRED(), NULL);
+ if (error)
+ goto out;
+ open_done = 1;
+
+ /*
+ * Truncate if required.
+ */
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
+ vattr.va_size = 0;
+ vattr.va_mask = AT_SIZE;
+ if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
+ goto out;
+ }
+out:
+ ASSERT(vp->v_count > 0);
+
+ if (error) {
+ if (open_done) {
+ (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
+ NULL);
+ open_done = 0;
+ }
+ VN_RELE(vp);
+ } else
+ *vpp = vp;
+ return (error);
+}
+
+
+/*
+ * Create a vnode (makenode).
+ */
+int
+vn_create(
+ char *pnamep,
+ enum uio_seg seg,
+ struct vattr *vap,
+ enum vcexcl excl,
+ int mode,
+ struct vnode **vpp,
+ enum create why,
+ int flag,
+ mode_t umask)
+{
+ struct vnode *dvp = NULL; /* ptr to parent dir vnode */
+ char *lastcomp = NULL;
+ int error;
+
+ ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
+
+ flag &= ~(FNOFOLLOW|FNOLINKS);
+
+ *vpp = NULL;
+
+ /*
+ * Lookup directory and last component
+ */
+ error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
+ if (error != 0) {
+ /* dir not found */
+ return (error);
+ }
+
+ /*
+ * If default ACLs are defined for the directory don't apply the
+ * umask if umask is passed.
+ */
+
+ if (umask) {
+ /*
+ * Apply the umask if no default ACLs...
+ */
+ vap->va_mode &= ~umask;
+ }
+
+ if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ /*
+ * Call mkdir() if specified, otherwise create().
+ */
+ if (why == CRMKDIR) {
+ /*
+ * N.B., if vn_createat() ever requests
+ * case-insensitive behavior then it will need
+ * to be passed to VOP_MKDIR(). VOP_CREATE()
+ * will already get it via "flag"
+ */
+ error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
+ NULL, 0, NULL);
+ } else {
+ error = VOP_CREATE(dvp, lastcomp, vap,
+ excl, mode, vpp, CRED(), flag, NULL, NULL);
+ }
+
+out:
+ if (dvp != NULL)
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c
new file mode 100644
index 0000000000..5ff428593d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c
@@ -0,0 +1,123 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Portions of code from both of:
+ * syscall/rename.c
+ * fs/vnode.c
+ * heavily modified for this use.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <fs/fs_subr.h>
+#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
+#include <sys/time.h>
+
+#include <libfksmbfs.h>
+
+int
+fake_rename(char *frompath, char *topath)
+{
+ vnode_t *fdvp = NULL;
+ vnode_t *tdvp = NULL;
+ char *fname = NULL;
+ char *tname = NULL;
+ int error;
+
+ /*
+ * Lookup to and from directories.
+ */
+ if ((error = fake_lookup_dir(frompath, &fdvp, &fname)) != 0)
+ goto out;
+ if ((error = fake_lookup_dir(topath, &tdvp, &tname)) != 0)
+ goto out;
+
+ /*
+ * Make sure both the from vnode directory and the to directory
+ * are in the same vfs and the to directory is writable.
+ */
+ if (fdvp != tdvp && fdvp->v_vfsp != tdvp->v_vfsp) {
+ error = EXDEV;
+ goto out;
+ }
+ if (tdvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ /*
+ * Do the rename.
+ */
+ error = VOP_RENAME(fdvp, fname, tdvp, tname, CRED(), NULL, 0);
+
+out:
+ if (fdvp)
+ VN_RELE(fdvp);
+ if (tdvp)
+ VN_RELE(tdvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c
new file mode 100644
index 0000000000..33a63a16dc
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+
+#include <libfksmbfs.h>
+
+#define set_errno(e) (-(e))
+
+ssize_t
+fake_pread(vnode_t *vp, void *cbuf, size_t count, off_t offset)
+{
+ struct uio auio;
+ struct iovec aiov;
+ int fflag, ioflag, rwflag;
+ ssize_t bcount;
+ int error = 0;
+ u_offset_t fileoff = (u_offset_t)(ulong_t)offset;
+ const u_offset_t maxoff = MAXOFF32_T;
+
+ if ((bcount = (ssize_t)count) < 0)
+ return (set_errno(EINVAL));
+ fflag = FREAD;
+
+ rwflag = 0;
+
+ if (vp->v_type == VREG) {
+
+ if (bcount == 0)
+ goto out;
+
+ /*
+ * Return EINVAL if an invalid offset comes to pread.
+ * Negative offset from user will cause this error.
+ */
+
+ if (fileoff > maxoff) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Limit offset such that we don't read or write
+ * a file beyond the maximum offset representable in
+ * an off_t structure.
+ */
+ if (fileoff + bcount > maxoff)
+ bcount = (ssize_t)((offset_t)maxoff - fileoff);
+ } else if (vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto out;
+ }
+
+ aiov.iov_base = cbuf;
+ aiov.iov_len = bcount;
+ (void) VOP_RWLOCK(vp, rwflag, NULL);
+ auio.uio_loffset = fileoff;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = bcount;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_llimit = MAXOFFSET_T;
+ auio.uio_fmode = fflag;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC);
+
+ /* If read sync is not asked for, filter sync flags */
+ if ((ioflag & FRSYNC) == 0)
+ ioflag &= ~(FSYNC|FDSYNC);
+ error = VOP_READ(vp, &auio, ioflag, CRED(), NULL);
+ bcount -= auio.uio_resid;
+ VOP_RWUNLOCK(vp, rwflag, NULL);
+
+ if (error == EINTR && bcount != 0)
+ error = 0;
+out:
+ if (error)
+ return (set_errno(error));
+ return (bcount);
+}
+
+ssize_t
+fake_pwrite(vnode_t *vp, void *cbuf, size_t count, off_t offset)
+{
+ struct uio auio;
+ struct iovec aiov;
+ int fflag, ioflag, rwflag;
+ ssize_t bcount;
+ int error = 0;
+ u_offset_t fileoff = (u_offset_t)(ulong_t)offset;
+ const u_offset_t maxoff = MAXOFF32_T;
+
+ if ((bcount = (ssize_t)count) < 0)
+ return (set_errno(EINVAL));
+ fflag = FREAD | FWRITE;
+
+ rwflag = 1;
+
+ if (vp->v_type == VREG) {
+
+ if (bcount == 0)
+ goto out;
+
+ /*
+ * return EINVAL for offsets that cannot be
+ * represented in an off_t.
+ */
+ if (fileoff > maxoff) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Don't allow pwrite to cause file sizes to exceed
+ * maxoff.
+ */
+ if (fileoff == maxoff) {
+ error = EFBIG;
+ goto out;
+ }
+ if (fileoff + count > maxoff)
+ bcount = (ssize_t)((u_offset_t)maxoff - fileoff);
+ } else if (vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto out;
+ }
+
+ aiov.iov_base = cbuf;
+ aiov.iov_len = bcount;
+ (void) VOP_RWLOCK(vp, rwflag, NULL);
+ auio.uio_loffset = fileoff;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = bcount;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_llimit = MAXOFFSET_T;
+ auio.uio_fmode = fflag;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ /*
+ * The SUSv4 POSIX specification states:
+ * The pwrite() function shall be equivalent to write(), except
+ * that it writes into a given position and does not change
+ * the file offset (regardless of whether O_APPEND is set).
+ * To make this be true, we omit the FAPPEND flag from ioflag.
+ */
+ ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
+
+ error = VOP_WRITE(vp, &auio, ioflag, CRED(), NULL);
+ bcount -= auio.uio_resid;
+ VOP_RWUNLOCK(vp, rwflag, NULL);
+
+ if (error == EINTR && bcount != 0)
+ error = 0;
+out:
+ if (error)
+ return (set_errno(error));
+ return (bcount);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c
new file mode 100644
index 0000000000..5b074e2be9
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+/*
+ * Get file attribute information through a file name or a file descriptor.
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/pathname.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/mode.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <fs/fs_subr.h>
+
+#include <libfksmbfs.h>
+
+int
+fake_stat(vnode_t *vp, struct stat64 *ubp, int flag)
+{
+ cred_t *cr = CRED();
+ struct vfssw *vswp;
+ struct stat64 lsb;
+ vattr_t vattr;
+ int error;
+
+ vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
+ return (error);
+
+ bzero(&lsb, sizeof (lsb));
+ lsb.st_dev = vattr.va_fsid;
+ lsb.st_ino = vattr.va_nodeid;
+ lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
+ lsb.st_nlink = vattr.va_nlink;
+ lsb.st_uid = vattr.va_uid;
+ lsb.st_gid = vattr.va_gid;
+ lsb.st_rdev = vattr.va_rdev;
+ lsb.st_size = vattr.va_size;
+ lsb.st_atim = vattr.va_atime;
+ lsb.st_mtim = vattr.va_mtime;
+ lsb.st_ctim = vattr.va_ctime;
+ lsb.st_blksize = vattr.va_blksize;
+ lsb.st_blocks = vattr.va_nblocks;
+ if (vp->v_vfsp != NULL) {
+ vswp = &vfssw[vp->v_vfsp->vfs_fstype];
+ if (vswp->vsw_name && *vswp->vsw_name)
+ (void) strcpy(lsb.st_fstype, vswp->vsw_name);
+ }
+ if (copyout(&lsb, ubp, sizeof (lsb)))
+ return (EFAULT);
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c
new file mode 100644
index 0000000000..4c35620d29
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+/*
+ * Modified version of syscall/unlink.c
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+
+#include <libfksmbfs.h>
+
+/*
+ * Unlink a file from a directory
+ * Like syscall/unlinkat.c
+ */
+int
+fake_unlink(char *path, int flags)
+{
+ vnode_t *dvp = NULL;
+ char *lastcomp = NULL;
+ int error;
+
+ if (path == NULL)
+ return (EFAULT);
+
+ error = fake_lookup_dir(path, &dvp, &lastcomp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Some logic from vn_removeat() here
+ */
+ if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ if (flags == AT_REMOVEDIR) {
+ error = VOP_RMDIR(dvp, lastcomp, NULL, CRED(), NULL, 0);
+ } else {
+ error = VOP_REMOVE(dvp, lastcomp, CRED(), NULL, 0);
+ }
+
+out:
+ if (dvp != NULL)
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c
new file mode 100644
index 0000000000..cc63b01ee1
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c
@@ -0,0 +1,2155 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * This file contains those functions from fs/vfs.c that can be
+ * used with relatively little change. Functions that differ
+ * significantly from that are in other files.
+ */
+
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/user.h>
+#include <sys/fstyp.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/fem.h>
+#include <sys/mntent.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/statfs.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/dnlc.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/atomic.h>
+#include <sys/cmn_err.h>
+#include <sys/buf.h>
+#include <sys/debug.h>
+#include <sys/vnode.h>
+#include <sys/ddi.h>
+#include <sys/pathname.h>
+#include <sys/poll.h>
+#include <sys/sunddi.h>
+#include <sys/sysmacros.h>
+#include <sys/zone.h>
+#include <sys/policy.h>
+#include <sys/attr.h>
+#include <fs/fs_subr.h>
+
+#include <libfksmbfs.h>
+
+static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
+static void vfs_setmntopt_nolock(mntopts_t *, const char *,
+ const char *, int, int);
+static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
+// static void vfs_freemnttab(struct vfs *);
+static void vfs_freeopt(mntopt_t *);
+static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
+static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
+static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
+// static void vfs_createopttbl_extend(mntopts_t *, const char *,
+// const mntopts_t *);
+// static char **vfs_copycancelopt_extend(char **const, int);
+static void vfs_freecancelopt(char **);
+
+/*
+ * VFS global data.
+ */
+vnode_t *rootdir; /* pointer to root inode vnode. */
+struct vfs *rootvfs = NULL; /* pointer to root vfs; head of VFS list. */
+static krwlock_t vfslist;
+struct vfs *zone_vfslist; /* list of FS's mounted in zone */
+
+/* from os/vfs_conf.c */
+const int nfstype = 5;
+struct vfssw vfssw[10] = {
+ { "BADVFS" }, /* 0:invalid */
+ { "" }, /* reserved for loadable fs */
+ { "" },
+ { "" },
+ { "" },
+};
+
+/*
+ * Table for generic options recognized in the VFS layer and acted
+ * on at this level before parsing file system specific options.
+ * The nosuid option is stronger than any of the devices and setuid
+ * options, so those are canceled when nosuid is seen.
+ *
+ * All options which are added here need to be added to the
+ * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
+ */
+/*
+ * VFS Mount options table
+ */
+static char *ro_cancel[] = { MNTOPT_RW, NULL };
+static char *rw_cancel[] = { MNTOPT_RO, NULL };
+static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
+static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
+ MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
+static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
+static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
+static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
+static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
+static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
+static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
+static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
+static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
+
+static const mntopt_t mntopts[] = {
+/*
+ * option name cancel options default arg flags
+ */
+ { MNTOPT_REMOUNT, NULL, NULL,
+ MO_NODISPLAY, (void *)0 },
+ { MNTOPT_RO, ro_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_RW, rw_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_SUID, suid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOSUID, nosuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_DEVICES, devices_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NODEVICES, nodevices_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_SETUID, setuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOSETUID, nosetuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NBMAND, nbmand_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NONBMAND, nonbmand_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_EXEC, exec_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOEXEC, noexec_cancel, NULL, 0,
+ (void *)0 },
+};
+
+const mntopts_t vfs_mntopts = {
+ sizeof (mntopts) / sizeof (mntopt_t),
+ (mntopt_t *)&mntopts[0]
+};
+
+/*
+ * File system operation dispatch functions.
+ */
+
+int
+fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
+}
+
+int
+fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
+}
+
+int
+fsop_root(vfs_t *vfsp, vnode_t **vpp)
+{
+ return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
+}
+
+int
+fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
+{
+ return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
+}
+
+int
+fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
+}
+
+int
+fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
+{
+ return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
+}
+
+int
+fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
+{
+ return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
+}
+
+void
+fsop_freefs(vfs_t *vfsp)
+{
+ (*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
+}
+
+int
+fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
+{
+ return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
+}
+
+int
+fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
+{
+ ASSERT((fstype >= 0) && (fstype < nfstype));
+
+ if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
+ return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
+ else
+ return (ENOTSUP);
+}
+
+/*
+ * File system initialization. vfs_setfsops() must be called from a file
+ * system's init routine.
+ */
+
+static int
+fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
+ int *unused_ops)
+{
+ static const fs_operation_trans_def_t vfs_ops_table[] = {
+ VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
+ (fs_generic_func_p) fs_sync,
+ (fs_generic_func_p) fs_sync, /* No errors allowed */
+
+ VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
+ (fs_generic_func_p)fs_freevfs,
+ (fs_generic_func_p)fs_freevfs, /* Shouldn't fail */
+
+ VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
+ (fs_generic_func_p)fs_nosys,
+ (fs_generic_func_p)fs_nosys,
+
+ NULL, 0, NULL, NULL
+ };
+
+ return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
+}
+
+/* zfs_boot_init() */
+
+int
+vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
+{
+ int error;
+ int unused_ops;
+
+ /*
+ * Verify that fstype refers to a valid fs. Note that
+ * 0 is valid since it's used to set "stray" ops.
+ */
+ if ((fstype < 0) || (fstype >= nfstype))
+ return (EINVAL);
+
+ if (!ALLOCATED_VFSSW(&vfssw[fstype]))
+ return (EINVAL);
+
+ /* Set up the operations vector. */
+
+ error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
+
+ if (error != 0)
+ return (error);
+
+ vfssw[fstype].vsw_flag |= VSW_INSTALLED;
+
+ if (actual != NULL)
+ *actual = &vfssw[fstype].vsw_vfsops;
+
+#if DEBUG
+ if (unused_ops != 0)
+ cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
+ "but not used", vfssw[fstype].vsw_name, unused_ops);
+#endif
+
+ return (0);
+}
+
+int
+vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
+{
+ int error;
+ int unused_ops;
+
+ *actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
+
+ error = fs_copyfsops(template, *actual, &unused_ops);
+ if (error != 0) {
+ kmem_free(*actual, sizeof (vfsops_t));
+ *actual = NULL;
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Free a vfsops structure created as a result of vfs_makefsops().
+ * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
+ * vfs_freevfsops_by_type().
+ */
+void
+vfs_freevfsops(vfsops_t *vfsops)
+{
+ kmem_free(vfsops, sizeof (vfsops_t));
+}
+
+/*
+ * Since the vfsops structure is part of the vfssw table and wasn't
+ * really allocated, we're not really freeing anything. We keep
+ * the name for consistency with vfs_freevfsops(). We do, however,
+ * need to take care of a little bookkeeping.
+ * NOTE: For a vfsops structure created by vfs_setfsops(), use
+ * vfs_freevfsops_by_type().
+ */
+int
+vfs_freevfsops_by_type(int fstype)
+{
+
+ /* Verify that fstype refers to a loaded fs (and not fsid 0). */
+ if ((fstype <= 0) || (fstype >= nfstype))
+ return (EINVAL);
+
+ WLOCK_VFSSW();
+ if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
+ WUNLOCK_VFSSW();
+ return (EINVAL);
+ }
+
+ vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
+ WUNLOCK_VFSSW();
+
+ return (0);
+}
+
+/* Support routines used to reference vfs_op */
+
+/* Set the operations vector for a vfs */
+void
+vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
+{
+
+ ASSERT(vfsp != NULL);
+ ASSERT(vfsops != NULL);
+
+ vfsp->vfs_op = vfsops;
+}
+
+/* Retrieve the operations vector for a vfs */
+vfsops_t *
+vfs_getops(vfs_t *vfsp)
+{
+
+ ASSERT(vfsp != NULL);
+
+ return (vfsp->vfs_op);
+}
+
+/*
+ * Returns non-zero (1) if the vfsops matches that of the vfs.
+ * Returns zero (0) if not.
+ */
+int
+vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
+{
+ return (vfs_getops(vfsp) == vfsops);
+}
+
+/*
+ * Returns non-zero (1) if the file system has installed a non-default,
+ * non-error vfs_sync routine. Returns zero (0) otherwise.
+ */
+int
+vfs_can_sync(vfs_t *vfsp)
+{
+ /* vfs_sync() routine is not the default/error function */
+ return (vfs_getops(vfsp)->vfs_sync != fs_sync);
+}
+
+/*
+ * Initialize a vfs structure.
+ */
+void
+vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
+{
+ /* Always do full init, like vfs_alloc() */
+ bzero(vfsp, sizeof (vfs_t));
+ vfsp->vfs_count = 0;
+ vfsp->vfs_next = vfsp;
+ vfsp->vfs_prev = vfsp;
+ vfsp->vfs_zone_next = vfsp;
+ vfsp->vfs_zone_prev = vfsp;
+ vfsp->vfs_lofi_id = 0;
+ sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
+ vfsimpl_setup(vfsp);
+ vfsp->vfs_data = (data);
+ vfs_setops((vfsp), (op));
+}
+
+/*
+ * Allocate and initialize the vfs implementation private data
+ * structure, vfs_impl_t.
+ */
+void
+vfsimpl_setup(vfs_t *vfsp)
+{
+ int i;
+
+ if (vfsp->vfs_implp != NULL) {
+ return;
+ }
+
+ vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
+ /* Note that these are #define'd in vfs.h */
+ vfsp->vfs_vskap = NULL;
+ vfsp->vfs_fstypevsp = NULL;
+
+ /* Set size of counted array, then zero the array */
+ vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
+ for (i = 1; i < VFS_FEATURE_MAXSZ; i++) {
+ vfsp->vfs_featureset[i] = 0;
+ }
+}
+
+/*
+ * Release the vfs_impl_t structure, if it exists. Some unbundled
+ * filesystems may not use the newer version of vfs and thus
+ * would not contain this implementation private data structure.
+ */
+void
+vfsimpl_teardown(vfs_t *vfsp)
+{
+ vfs_impl_t *vip = vfsp->vfs_implp;
+
+ if (vip == NULL)
+ return;
+
+ kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
+ vfsp->vfs_implp = NULL;
+}
+
+/*
+ * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
+ * fstatvfs, and sysfs moved to common/syscall.
+ */
+
+// vfs_sync, sync
+
+/*
+ * External routines.
+ */
+
+krwlock_t vfssw_lock; /* lock accesses to vfssw */
+
+/*
+ * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(),
+ * but otherwise should be accessed only via vfs_list_lock() and
+ * vfs_list_unlock(). Also used to protect the timestamp for mods to the list.
+ */
+static krwlock_t vfslist;
+
+// vfs_mountdevices(void)
+// vfs_mountdev1(void)
+// vfs_mountfs()
+// vfs_mountroot()
+// lofi_add, lofi_remove
+
+
+/*
+ * Mount the FS for the test jig. Based on domount()
+ */
+int
+fake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp)
+{
+ vnode_t *vp;
+ struct cred *credp;
+ struct vfssw *vswp;
+ vfsops_t *vfsops;
+ struct vfs *vfsp = NULL;
+ mntopts_t mnt_mntopts;
+ int error = 0;
+ int copyout_error = 0;
+ char *opts = uap->optptr;
+ char *inargs = opts;
+ int optlen = uap->optlen;
+
+ credp = CRED();
+
+ /*
+ * Test jig specific: mount on rootdir
+ */
+ if (rootvfs != NULL)
+ return (EBUSY);
+ vp = rootdir;
+
+ /*
+ * The v_flag value for the mount point vp is permanently set
+ * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
+ * for mount point locking.
+ */
+ mutex_enter(&vp->v_lock);
+ vp->v_flag |= VVFSLOCK;
+ mutex_exit(&vp->v_lock);
+
+ mnt_mntopts.mo_count = 0;
+
+ /*
+ * Find the ops vector to use to invoke the file system-specific mount
+ * method. If the fsname argument is non-NULL, use it directly.
+ */
+ if ((vswp = vfs_getvfssw(fsname)) == NULL) {
+ return (EINVAL);
+ }
+ if (!VFS_INSTALLED(vswp))
+ return (EINVAL);
+
+ // secpolicy_fs_allowed_mount(fsname)
+
+ vfsops = &vswp->vsw_vfsops;
+
+ vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
+
+ /*
+ * Fetch mount options and parse them for generic vfs options
+ */
+ if (uap->flags & MS_OPTIONSTR) {
+ /*
+ * Limit the buffer size
+ */
+ if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
+ error = EINVAL;
+ goto errout;
+ }
+ if ((uap->flags & MS_SYSSPACE) == 0) {
+ inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
+ inargs[0] = '\0';
+ if (optlen) {
+ error = copyinstr(opts, inargs, (size_t)optlen,
+ NULL);
+ if (error) {
+ goto errout;
+ }
+ }
+ }
+ vfs_parsemntopts(&mnt_mntopts, inargs, 0);
+ }
+ /*
+ * Flag bits override the options string.
+ */
+ if (uap->flags & MS_REMOUNT)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
+ if (uap->flags & MS_RDONLY)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
+ if (uap->flags & MS_NOSUID)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+
+ /*
+ * Check if this is a remount; must be set in the option string and
+ * the file system must support a remount option.
+ */
+ if (vfs_optionisset_nolock(&mnt_mntopts,
+ MNTOPT_REMOUNT, NULL)) {
+ /* disallow here */
+ error = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * uap->flags and vfs_optionisset() should agree.
+ */
+ if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
+ uap->flags |= MS_RDONLY;
+ }
+ if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
+ uap->flags |= MS_NOSUID;
+ }
+ // nbmand ...
+
+ /*
+ * If we are splicing the fs into the namespace,
+ * perform mount point checks...
+ * (always splice=0 here)
+ */
+
+ if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
+ uap->dataptr = NULL;
+ uap->datalen = 0;
+ }
+
+ /*
+ * If this is a remount, ... (never here)
+ */
+ vfsp = vfs_alloc(KM_SLEEP);
+ VFS_INIT(vfsp, vfsops, NULL);
+
+ VFS_HOLD(vfsp);
+
+ // lofi_add(fsname, vfsp, &mnt_mntopts, uap)
+
+ /*
+ * PRIV_SYS_MOUNT doesn't mean you can become root.
+ */
+ uap->flags |= MS_NOSUID;
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+
+ /*
+ * The vfs_reflock...
+ */
+
+ /*
+ * Lock the vfs...
+ */
+ if ((error = vfs_lock(vfsp)) != 0) {
+ vfs_free(vfsp);
+ vfsp = NULL;
+ goto errout;
+ }
+
+ /*
+ * Add device to mount in progress table...
+ */
+ /*
+ * Invalidate cached entry for the mount point.
+ */
+
+ /*
+ * If have an option string but the filesystem doesn't supply a
+ * prototype options table, create a table...
+ */
+
+ /*
+ * Serialize with zone state transitions...
+ */
+
+ // mount_in_progress(zone);
+
+ /*
+ * Instantiate (or reinstantiate) the file system...
+ */
+ vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
+
+ vfs_setresource(vfsp, uap->spec, 0);
+ vfs_setmntpoint(vfsp, uap->dir, 0);
+
+ /*
+ * going to mount on this vnode, so notify.
+ */
+ // vnevent_mountedover(vp, NULL);
+ error = VFS_MOUNT(vfsp, vp, uap, credp);
+
+ if (uap->flags & MS_RDONLY)
+ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+ if (uap->flags & MS_NOSUID)
+ vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
+ if (uap->flags & MS_GLOBAL)
+ vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
+
+ if (error) {
+ // lofi_remove(vfsp);
+
+ // (remount == 0)
+ vfs_unlock(vfsp);
+ // vfs_freemnttab(vfsp);
+ vfs_free(vfsp);
+ vfsp = NULL;
+ } else {
+ /*
+ * Set the mount time to now
+ */
+ // vfsp->vfs_mtime = ddi_get_time();
+ // if (remount) ...
+ // else if (splice) vfs_add(vp, vfsp, flags)
+ // else VFS_HOLD(vfsp);
+
+ /*
+ * Test jig specific:
+ * Do sort of like vfs_add for vp=rootdir
+ * Already have hold on vp.
+ */
+ vfsp->vfs_vnodecovered = vp;
+ vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
+ VFS_HOLD(vfsp);
+ rootvfs = vfsp;
+
+ /*
+ * Set flags for global options encountered
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
+ vfsp->vfs_flag |= VFS_RDONLY;
+ else
+ vfsp->vfs_flag &= ~VFS_RDONLY;
+ if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
+ vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
+ } else {
+ if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
+ vfsp->vfs_flag |= VFS_NODEVICES;
+ else
+ vfsp->vfs_flag &= ~VFS_NODEVICES;
+ if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
+ vfsp->vfs_flag |= VFS_NOSETUID;
+ else
+ vfsp->vfs_flag &= ~VFS_NOSETUID;
+ }
+ if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
+ vfsp->vfs_flag |= VFS_NBMAND;
+ else
+ vfsp->vfs_flag &= ~VFS_NBMAND;
+
+ if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
+ vfsp->vfs_flag |= VFS_XATTR;
+ else
+ vfsp->vfs_flag &= ~VFS_XATTR;
+
+ if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
+ vfsp->vfs_flag |= VFS_NOEXEC;
+ else
+ vfsp->vfs_flag &= ~VFS_NOEXEC;
+
+ /*
+ * Now construct the output option string of options
+ * we recognized.
+ */
+ if (uap->flags & MS_OPTIONSTR) {
+ vfs_list_read_lock();
+ copyout_error = vfs_buildoptionstr(
+ &vfsp->vfs_mntopts, inargs, optlen);
+ vfs_list_unlock();
+ if (copyout_error == 0 &&
+ (uap->flags & MS_SYSSPACE) == 0) {
+ copyout_error = copyout(inargs, opts, optlen);
+ }
+ }
+
+ /*
+ * If this isn't a remount, set up the vopstats...
+ */
+ if (vswp->vsw_flag & VSW_XID)
+ vfsp->vfs_flag |= VFS_XID;
+
+ vfs_unlock(vfsp);
+
+ /*
+ * Test jig specicific:
+ * Replace rootdir with the mounted root.
+ */
+ error = VFS_ROOT(vfsp, &rootdir);
+ if (error != 0) {
+ panic("fake_domount, get root %d\n", error);
+ }
+ }
+ // mount_completed(zone);
+ // zone_rele(zone);
+
+ // if (splice)
+ // vn_vfsunlock(vp);
+
+ if ((error == 0) && (copyout_error == 0)) {
+ /* get_vskstat_anchor() */
+ /* Return vfsp to caller. */
+ *vfspp = vfsp;
+ }
+errout:
+ vfs_freeopttbl(&mnt_mntopts);
+ /* resource, mountpt not allocated */
+ /* no addmip, delmip */
+ ASSERT(vswp != NULL);
+ vfs_unrefvfssw(vswp);
+ if (inargs != opts)
+ kmem_free(inargs, MAX_MNTOPT_STR);
+ if (copyout_error) {
+ if (vfsp != NULL) {
+ // lofi_remove(vfsp);
+ VFS_RELE(vfsp);
+ }
+ error = copyout_error;
+ }
+ return (error);
+}
+
+
+static void
+vfs_setpath(
+ struct vfs *vfsp, /* vfs being updated */
+ refstr_t **refp, /* Ref-count string to contain the new path */
+ const char *newpath, /* Path to add to refp (above) */
+ uint32_t flag) /* flag */
+{
+ // size_t len;
+ refstr_t *ref;
+ // char *sp;
+ int have_list_lock = 0;
+
+ ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
+
+ /*
+ * New path must be less than MAXPATHLEN because mntfs
+ * will only display up to MAXPATHLEN bytes. This is currently
+ * safe, because domount() uses pn_get(), and other callers
+ * similarly cap the size to fewer than MAXPATHLEN bytes.
+ */
+
+ ASSERT(strlen(newpath) < MAXPATHLEN);
+
+ /* mntfs requires consistency while vfs list lock is held */
+
+ if (VFS_ON_LIST(vfsp)) {
+ have_list_lock = 1;
+ vfs_list_lock();
+ }
+
+ if (*refp != NULL)
+ refstr_rele(*refp);
+
+ /*
+ * If we are in a non-global zone... (do something else)
+ */
+ ref = refstr_alloc(newpath);
+ *refp = ref;
+
+ if (have_list_lock) {
+ vfs_mnttab_modtimeupd();
+ vfs_list_unlock();
+ }
+}
+
+/*
+ * Record a mounted resource name in a vfs structure.
+ * If vfsp is already mounted, caller must hold the vfs lock.
+ */
+void
+vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
+{
+ if (resource == NULL || resource[0] == '\0')
+ resource = VFS_NORESOURCE;
+ vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
+}
+
+/*
+ * Record a mount point name in a vfs structure.
+ * If vfsp is already mounted, caller must hold the vfs lock.
+ */
+void
+vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
+{
+ if (mntpt == NULL || mntpt[0] == '\0')
+ mntpt = VFS_NOMNTPT;
+ vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
+}
+
+/* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
+
+refstr_t *
+vfs_getresource(const struct vfs *vfsp)
+{
+ refstr_t *resource;
+
+ vfs_list_read_lock();
+ resource = vfsp->vfs_resource;
+ refstr_hold(resource);
+ vfs_list_unlock();
+
+ return (resource);
+}
+
+/* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
+
+refstr_t *
+vfs_getmntpoint(const struct vfs *vfsp)
+{
+ refstr_t *mntpt;
+
+ vfs_list_read_lock();
+ mntpt = vfsp->vfs_mntpt;
+ refstr_hold(mntpt);
+ vfs_list_unlock();
+
+ return (mntpt);
+}
+
+// vfs_createopttbl_extend
+// vfs_createopttbl
+
+/*
+ * Swap two mount options tables
+ */
+static void
+vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
+{
+ uint_t tmpcnt;
+ mntopt_t *tmplist;
+
+ tmpcnt = optbl2->mo_count;
+ tmplist = optbl2->mo_list;
+ optbl2->mo_count = optbl1->mo_count;
+ optbl2->mo_list = optbl1->mo_list;
+ optbl1->mo_count = tmpcnt;
+ optbl1->mo_list = tmplist;
+}
+
+static void
+vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
+{
+ vfs_list_lock();
+ vfs_swapopttbl_nolock(optbl1, optbl2);
+ vfs_mnttab_modtimeupd();
+ vfs_list_unlock();
+}
+
+static char **
+vfs_copycancelopt_extend(char **const moc, int extend)
+{
+ int i = 0;
+ int j;
+ char **result;
+
+ if (moc != NULL) {
+ for (; moc[i] != NULL; i++)
+ /* count number of options to cancel */;
+ }
+
+ if (i + extend == 0)
+ return (NULL);
+
+ result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
+
+ for (j = 0; j < i; j++) {
+ result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
+ (void) strcpy(result[j], moc[j]);
+ }
+ for (; j <= i + extend; j++)
+ result[j] = NULL;
+
+ return (result);
+}
+
+static void
+vfs_copyopt(const mntopt_t *s, mntopt_t *d)
+{
+ char *sp, *dp;
+
+ d->mo_flags = s->mo_flags;
+ d->mo_data = s->mo_data;
+ sp = s->mo_name;
+ if (sp != NULL) {
+ dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
+ (void) strcpy(dp, sp);
+ d->mo_name = dp;
+ } else {
+ d->mo_name = NULL; /* should never happen */
+ }
+
+ d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
+
+ sp = s->mo_arg;
+ if (sp != NULL) {
+ dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
+ (void) strcpy(dp, sp);
+ d->mo_arg = dp;
+ } else {
+ d->mo_arg = NULL;
+ }
+}
+
+// vfs_copyopttbl_extend
+// vfs_copyopttbl
+
+/*
+ * Copy a mount options table, possibly allocating some spare
+ * slots at the end. It is permissible to copy_extend the NULL table.
+ */
+static void
+vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
+{
+ uint_t i, count;
+ mntopt_t *motbl;
+
+ /*
+ * Clear out any existing stuff in the options table being initialized
+ */
+ vfs_freeopttbl(dmo);
+ count = (smo == NULL) ? 0 : smo->mo_count;
+ if ((count + extra) == 0) /* nothing to do */
+ return;
+ dmo->mo_count = count + extra;
+ motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
+ dmo->mo_list = motbl;
+ for (i = 0; i < count; i++) {
+ vfs_copyopt(&smo->mo_list[i], &motbl[i]);
+ }
+ for (i = count; i < count + extra; i++) {
+ motbl[i].mo_flags = MO_EMPTY;
+ }
+}
+
+/*
+ * Copy a mount options table.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect smo and dmo.
+ */
+void
+vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
+{
+ vfs_copyopttbl_extend(smo, dmo, 0);
+}
+
+static char **
+vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
+{
+ int c1 = 0;
+ int c2 = 0;
+ char **result;
+ char **sp1, **sp2, **dp;
+
+ /*
+ * First we count both lists of cancel options.
+ * If either is NULL or has no elements, we return a copy of
+ * the other.
+ */
+ if (mop1->mo_cancel != NULL) {
+ for (; mop1->mo_cancel[c1] != NULL; c1++)
+ /* count cancel options in mop1 */;
+ }
+
+ if (c1 == 0)
+ return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
+
+ if (mop2->mo_cancel != NULL) {
+ for (; mop2->mo_cancel[c2] != NULL; c2++)
+ /* count cancel options in mop2 */;
+ }
+
+ result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
+
+ if (c2 == 0)
+ return (result);
+
+ /*
+ * When we get here, we've got two sets of cancel options;
+ * we need to merge the two sets. We know that the result
+ * array has "c1+c2+1" entries and in the end we might shrink
+ * it.
+ * Result now has a copy of the c1 entries from mop1; we'll
+ * now lookup all the entries of mop2 in mop1 and copy it if
+ * it is unique.
+ * This operation is O(n^2) but it's only called once per
+ * filesystem per duplicate option. This is a situation
+ * which doesn't arise with the filesystems in ON and
+ * n is generally 1.
+ */
+
+ dp = &result[c1];
+ for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
+ for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
+ if (strcmp(*sp1, *sp2) == 0)
+ break;
+ }
+ if (*sp1 == NULL) {
+ /*
+ * Option *sp2 not found in mop1, so copy it.
+ * The calls to vfs_copycancelopt_extend()
+ * guarantee that there's enough room.
+ */
+ *dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
+ (void) strcpy(*dp++, *sp2);
+ }
+ }
+ if (dp != &result[c1+c2]) {
+ size_t bytes = (dp - result + 1) * sizeof (char *);
+ char **nres = kmem_alloc(bytes, KM_SLEEP);
+
+ bcopy(result, nres, bytes);
+ kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
+ result = nres;
+ }
+ return (result);
+}
+
+/*
+ * Merge two mount option tables (outer and inner) into one. This is very
+ * similar to "merging" global variables and automatic variables in C.
+ *
+ * This isn't (and doesn't have to be) fast.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect omo, imo & dmo.
+ */
+void
+vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
+{
+ uint_t i, count;
+ mntopt_t *mop, *motbl;
+ uint_t freeidx;
+
+ /*
+ * First determine how much space we need to allocate.
+ */
+ count = omo->mo_count;
+ for (i = 0; i < imo->mo_count; i++) {
+ if (imo->mo_list[i].mo_flags & MO_EMPTY)
+ continue;
+ if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
+ count++;
+ }
+ ASSERT(count >= omo->mo_count &&
+ count <= omo->mo_count + imo->mo_count);
+ motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
+ for (i = 0; i < omo->mo_count; i++)
+ vfs_copyopt(&omo->mo_list[i], &motbl[i]);
+ freeidx = omo->mo_count;
+ for (i = 0; i < imo->mo_count; i++) {
+ if (imo->mo_list[i].mo_flags & MO_EMPTY)
+ continue;
+ if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
+ char **newcanp;
+ uint_t index = mop - omo->mo_list;
+
+ newcanp = vfs_mergecancelopts(mop, &motbl[index]);
+
+ vfs_freeopt(&motbl[index]);
+ vfs_copyopt(&imo->mo_list[i], &motbl[index]);
+
+ vfs_freecancelopt(motbl[index].mo_cancel);
+ motbl[index].mo_cancel = newcanp;
+ } else {
+ /*
+ * If it's a new option, just copy it over to the first
+ * free location.
+ */
+ vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
+ }
+ }
+ dmo->mo_count = count;
+ dmo->mo_list = motbl;
+}
+
+/*
+ * Functions to set and clear mount options in a mount options table.
+ */
+
+/*
+ * Clear a mount option, if it exists.
+ *
+ * The update_mnttab arg indicates whether mops is part of a vfs that is on
+ * the vfs list.
+ */
+static void
+vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name))
+ continue;
+ mop->mo_flags &= ~MO_SET;
+ if (mop->mo_arg != NULL) {
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+ }
+ mop->mo_arg = NULL;
+ if (update_mnttab)
+ vfs_mnttab_modtimeupd();
+ break;
+ }
+}
+
+void
+vfs_clearmntopt(struct vfs *vfsp, const char *opt)
+{
+ int gotlock = 0;
+
+ if (VFS_ON_LIST(vfsp)) {
+ gotlock = 1;
+ vfs_list_lock();
+ }
+ vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
+ if (gotlock)
+ vfs_list_unlock();
+}
+
+
+/*
+ * Set a mount option on...
+ */
+static void
+vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
+ const char *arg, int flags, int update_mnttab)
+{
+ mntopt_t *mop;
+ uint_t i, count;
+ char *sp;
+
+ ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
+
+ if (flags & VFS_CREATEOPT) {
+ if (vfs_hasopt(mops, opt) != NULL) {
+ flags &= ~VFS_CREATEOPT;
+ }
+ }
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY) {
+ if ((flags & VFS_CREATEOPT) == 0)
+ continue;
+ sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
+ (void) strcpy(sp, opt);
+ mop->mo_name = sp;
+ if (arg != NULL)
+ mop->mo_flags = MO_HASVALUE;
+ else
+ mop->mo_flags = 0;
+ } else if (strcmp(opt, mop->mo_name)) {
+ continue;
+ }
+ if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
+ break;
+ if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
+ sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
+ (void) strcpy(sp, arg);
+ } else {
+ sp = NULL;
+ }
+ if (mop->mo_arg != NULL)
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+ mop->mo_arg = sp;
+ if (flags & VFS_DISPLAY)
+ mop->mo_flags &= ~MO_NODISPLAY;
+ if (flags & VFS_NODISPLAY)
+ mop->mo_flags |= MO_NODISPLAY;
+ mop->mo_flags |= MO_SET;
+ if (mop->mo_cancel != NULL) {
+ char **cp;
+
+ for (cp = mop->mo_cancel; *cp != NULL; cp++)
+ vfs_clearmntopt_nolock(mops, *cp, 0);
+ }
+ if (update_mnttab)
+ vfs_mnttab_modtimeupd();
+ break;
+ }
+}
+
+void
+vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
+{
+ int gotlock = 0;
+
+ if (VFS_ON_LIST(vfsp)) {
+ gotlock = 1;
+ vfs_list_lock();
+ }
+ vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
+ if (gotlock)
+ vfs_list_unlock();
+}
+
+// vfs_addtag
+// vfs_settag
+// vfs_clrtag
+
+/*
+ * Function to parse an option string and fill in a mount options table.
+ * Unknown options are silently ignored. The input option string is modified
+ * by replacing separators with nulls. If the create flag is set, options
+ * not found in the table are just added on the fly. The table must have
+ * an option slot marked MO_EMPTY to add an option on the fly.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mops..
+ */
+void
+vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
+{
+ char *s = osp, *p, *nextop, *valp, *cp, *ep = NULL;
+ int setflg = VFS_NOFORCEOPT;
+
+ if (osp == NULL)
+ return;
+ while (*s != '\0') {
+ p = strchr(s, ','); /* find next option */
+ if (p == NULL) {
+ cp = NULL;
+ p = s + strlen(s);
+ } else {
+ cp = p; /* save location of comma */
+ *p++ = '\0'; /* mark end and point to next option */
+ }
+ nextop = p;
+ p = strchr(s, '='); /* look for value */
+ if (p == NULL) {
+ valp = NULL; /* no value supplied */
+ ep = NULL;
+ } else {
+ ep = p; /* save location of equals */
+ *p++ = '\0'; /* end option and point to value */
+ valp = p;
+ }
+ /*
+ * set option into options table
+ */
+ if (create)
+ setflg |= VFS_CREATEOPT;
+ vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
+ if (cp != NULL)
+ *cp = ','; /* restore the comma */
+ if (valp != NULL)
+ *ep = '='; /* restore the equals */
+ s = nextop;
+ }
+}
+
+/*
+ * Function to inquire if an option exists in a mount options table.
+ * Returns a pointer to the option if it exists, else NULL.
+ */
+struct mntopt *
+vfs_hasopt(const mntopts_t *mops, const char *opt)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name) == 0)
+ return (mop);
+ }
+ return (NULL);
+}
+
+/*
+ * Function to inquire if an option is set in a mount options table.
+ * Returns non-zero if set and fills in the arg pointer with a pointer to
+ * the argument string or NULL if there is no argument string.
+ */
+static int
+vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name))
+ continue;
+ if ((mop->mo_flags & MO_SET) == 0)
+ return (0);
+ if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
+ *argp = mop->mo_arg;
+ return (1);
+ }
+ return (0);
+}
+
+
+int
+vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
+{
+ int ret;
+
+ vfs_list_read_lock();
+ ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
+ vfs_list_unlock();
+ return (ret);
+}
+
+
+/*
+ * Construct a comma separated string of the options set in the given
+ * mount table, return the string in the given buffer. Return non-zero if
+ * the buffer would overflow.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mp.
+ */
+int
+vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
+{
+ char *cp;
+ uint_t i;
+
+ buf[0] = '\0';
+ cp = buf;
+ for (i = 0; i < mp->mo_count; i++) {
+ struct mntopt *mop;
+
+ mop = &mp->mo_list[i];
+ if (mop->mo_flags & MO_SET) {
+ int optlen, comma = 0;
+
+ if (buf[0] != '\0')
+ comma = 1;
+ optlen = strlen(mop->mo_name);
+ if (strlen(buf) + comma + optlen + 1 > len)
+ goto err;
+ if (comma)
+ *cp++ = ',';
+ (void) strcpy(cp, mop->mo_name);
+ cp += optlen;
+ /*
+ * Append option value if there is one
+ */
+ if (mop->mo_arg != NULL) {
+ int arglen;
+
+ arglen = strlen(mop->mo_arg);
+ if (strlen(buf) + arglen + 2 > len)
+ goto err;
+ *cp++ = '=';
+ (void) strcpy(cp, mop->mo_arg);
+ cp += arglen;
+ }
+ }
+ }
+ return (0);
+err:
+ return (EOVERFLOW);
+}
+
+static void
+vfs_freecancelopt(char **moc)
+{
+ if (moc != NULL) {
+ int ccnt = 0;
+ char **cp;
+
+ for (cp = moc; *cp != NULL; cp++) {
+ kmem_free(*cp, strlen(*cp) + 1);
+ ccnt++;
+ }
+ kmem_free(moc, (ccnt + 1) * sizeof (char *));
+ }
+}
+
+static void
+vfs_freeopt(mntopt_t *mop)
+{
+ if (mop->mo_name != NULL)
+ kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
+
+ vfs_freecancelopt(mop->mo_cancel);
+
+ if (mop->mo_arg != NULL)
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+}
+
+/*
+ * Free a mount options table
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mp.
+ */
+void
+vfs_freeopttbl(mntopts_t *mp)
+{
+ uint_t i, count;
+
+ count = mp->mo_count;
+ for (i = 0; i < count; i++) {
+ vfs_freeopt(&mp->mo_list[i]);
+ }
+ if (count) {
+ kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
+ mp->mo_count = 0;
+ mp->mo_list = NULL;
+ }
+}
+
+// vfs_mntdummyread
+// vfs_mntdummywrite
+// vfs_mntdummygetattr
+// vfs_mnttabvp_setup
+// vfs_mnttab_rwop
+// vfs_mnttab_writeop
+// vfs_mnttab_readop
+// vfs_freemnttab
+// vfs_mnttab_modtime
+// vfs_mnttab_poll
+// vfs_mono_time
+
+/*
+ * Update the mnttab modification time...
+ */
+void
+vfs_mnttab_modtimeupd()
+{
+}
+
+/*
+ * Unlike the real dounmount, we don't have
+ * vn_vfswlock_held(coveredvp)
+ */
+int
+fake_dounmount(struct vfs *vfsp, int flag)
+{
+ cred_t *cr = CRED();
+ vnode_t *coveredvp;
+ int error;
+
+ /*
+ * Get covered vnode. This will be NULL if the vfs is not linked
+ * into the file system name space (i.e., domount() with MNT_NOSPICE).
+ */
+ coveredvp = vfsp->vfs_vnodecovered;
+
+ /* For forcible umount, skip VFS_SYNC() since it may hang */
+ if ((flag & MS_FORCE) == 0)
+ (void) VFS_SYNC(vfsp, 0, cr);
+
+ /*
+ * Test-jig specific:
+ * Need to release rootdir before unmount or VFS_UNMOUNT
+ * may fail due to that node being active.
+ */
+ if (rootdir != NULL) {
+ ASSERT(rootdir != coveredvp);
+ VN_RELE(rootdir);
+ rootdir = NULL;
+ }
+
+ /*
+ * Lock the vfs to maintain fs status quo during unmount. This
+ * has to be done after the sync because ufs_update tries to acquire
+ * the vfs_reflock.
+ */
+ vfs_lock_wait(vfsp);
+
+ if ((error = VFS_UNMOUNT(vfsp, flag, cr)) != 0) {
+ int err2;
+ vfs_unlock(vfsp);
+ /* Get rootdir back */
+ err2 = VFS_ROOT(vfsp, &rootdir);
+ if (err2 != 0) {
+ panic("fake_dounmount, get root %d\n", err2);
+ }
+ } else {
+ /*
+ * Real dounmount does vfs_remove.
+ *
+ * Test-jig specific:
+ * Restore the covered rootdir,
+ * release the rootvfs hold and clear.
+ */
+ if (coveredvp != NULL) {
+ // vfs_list_remove(vfsp);
+ vfsp->vfs_vnodecovered = NULL;
+ rootdir = coveredvp;
+ }
+ if (rootvfs == vfsp) {
+ VFS_RELE(vfsp);
+ rootvfs = NULL;
+ }
+
+ /*
+ * Release the (final) reference to vfs
+ */
+ vfs_unlock(vfsp);
+ VFS_RELE(vfsp);
+ }
+ return (error);
+}
+
+// vfs_unmountall(void)
+// vfs_addmip
+// vfs_delmip
+// vfs_add
+// vfs_remove
+
+static krwlock_t vpvfsentry_ve_lock;
+
+/*
+ * Lock a filesystem to prevent access to it while mounting,
+ * unmounting and syncing. Return EBUSY immediately if lock
+ * can't be acquired.
+ */
+int
+vfs_lock(vfs_t *vfsp)
+{
+
+ if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER))
+ return (0);
+
+ return (EBUSY);
+}
+
+int
+vfs_rlock(vfs_t *vfsp)
+{
+
+ if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER))
+ return (0);
+
+ return (EBUSY);
+}
+
+void
+vfs_lock_wait(vfs_t *vfsp)
+{
+
+ rw_enter(&vpvfsentry_ve_lock, RW_WRITER);
+}
+
+void
+vfs_rlock_wait(vfs_t *vfsp)
+{
+ rw_enter(&vpvfsentry_ve_lock, RW_READER);
+}
+
+/*
+ * Unlock a locked filesystem.
+ */
+void
+vfs_unlock(vfs_t *vfsp)
+{
+
+ rw_exit(&vpvfsentry_ve_lock);
+}
+
+/*
+ * Utility routine that allows a filesystem to construct its
+ * fsid in "the usual way" - by munging some underlying dev_t and
+ * the filesystem type number into the 64-bit fsid. ...
+ */
+void
+vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
+{
+ if (!cmpldev((dev32_t *)&fsi->val[0], dev))
+ panic("device number too big for fsid!");
+ fsi->val[1] = val;
+}
+
+int
+vfs_lock_held(vfs_t *vfsp)
+{
+ int held;
+
+ held = rw_write_held(&vpvfsentry_ve_lock);
+
+ return (held);
+}
+
+// vfs_lock_owner
+
+/*
+ * vfs list locking.
+ */
+
+void
+vfs_list_lock()
+{
+ rw_enter(&vfslist, RW_WRITER);
+}
+
+void
+vfs_list_read_lock()
+{
+ rw_enter(&vfslist, RW_READER);
+}
+
+void
+vfs_list_unlock()
+{
+ rw_exit(&vfslist);
+}
+
+/*
+ * Low level worker routines for adding entries to and removing entries from
+ * the vfs list.
+ */
+
+// vfs_hash_add
+// vfs_hash_remove
+// vfs_list_add
+// vfs_list_remove
+// getvfs
+// vfs_devmounting
+
+/*
+ * Search the vfs list for a specified device. Returns 1, if entry is found
+ * or 0 if no suitable entry is found.
+ */
+
+int
+vfs_devismounted(dev_t dev)
+{
+ return (0);
+}
+
+// vfs_dev2vfsp
+// vfs_mntpoint2vfsp
+
+/*
+ * Search the vfs list for a specified vfsops.
+ * if vfs entry is found then return 1, else 0.
+ */
+int
+vfs_opsinuse(vfsops_t *ops)
+{
+ return (0);
+}
+
+/*
+ * Allocate an entry in vfssw for a file system type
+ */
+struct vfssw *
+allocate_vfssw(const char *type)
+{
+ struct vfssw *vswp;
+
+ if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
+ /*
+ * The vfssw table uses the empty string to identify an
+ * available entry; we cannot add any type which has
+ * a leading NUL. The string length is limited to
+ * the size of the st_fstype array in struct stat.
+ */
+ return (NULL);
+ }
+
+ ASSERT(VFSSW_WRITE_LOCKED());
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
+ if (!ALLOCATED_VFSSW(vswp)) {
+ vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
+ (void) strcpy(vswp->vsw_name, type);
+ ASSERT(vswp->vsw_count == 0);
+ vswp->vsw_count = 1;
+ mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
+ return (vswp);
+ }
+ return (NULL);
+}
+
+// vfs_to_modname
+// vfs_getvfssw
+
+/*
+ * Find a vfssw entry given a file system type name.
+ */
+struct vfssw *
+vfs_getvfssw(const char *type)
+{
+ struct vfssw *vswp;
+
+ if (type == NULL || *type == '\0')
+ return (NULL);
+
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
+ if (strcmp(type, vswp->vsw_name) == 0) {
+ return (vswp);
+ }
+ }
+
+ return (NULL);
+
+}
+
+/*
+ * Find a vfssw entry given a file system type name.
+ */
+struct vfssw *
+vfs_getvfsswbyname(const char *type)
+{
+ struct vfssw *vswp;
+
+ ASSERT(VFSSW_LOCKED());
+ if (type == NULL || *type == '\0')
+ return (NULL);
+
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
+ if (strcmp(type, vswp->vsw_name) == 0) {
+ vfs_refvfssw(vswp);
+ return (vswp);
+ }
+ }
+
+ return (NULL);
+}
+
+// vfs_getvfsswbyvfsops
+
+/*
+ * Reference a vfssw entry.
+ */
+void
+vfs_refvfssw(struct vfssw *vswp)
+{
+
+ mutex_enter(&vswp->vsw_lock);
+ vswp->vsw_count++;
+ mutex_exit(&vswp->vsw_lock);
+}
+
+/*
+ * Unreference a vfssw entry.
+ */
+void
+vfs_unrefvfssw(struct vfssw *vswp)
+{
+
+ mutex_enter(&vswp->vsw_lock);
+ vswp->vsw_count--;
+ mutex_exit(&vswp->vsw_lock);
+}
+
+// vfs_syncall
+
+/*
+ * Map VFS flags to statvfs flags. These shouldn't really be separate
+ * flags at all.
+ */
+uint_t
+vf_to_stf(uint_t vf)
+{
+ uint_t stf = 0;
+
+ if (vf & VFS_RDONLY)
+ stf |= ST_RDONLY;
+ if (vf & VFS_NOSETUID)
+ stf |= ST_NOSUID;
+ if (vf & VFS_NOTRUNC)
+ stf |= ST_NOTRUNC;
+
+ return (stf);
+}
+
+// vfsstray_sync
+// vfsstray
+// vfs_EIO
+// vfs_EIO_sync
+// EIO_vfs
+// EIO_vfsops
+
+#pragma init(vfsinit)
+
+/*
+ * Called from startup() to initialize all loaded vfs's
+ */
+void
+vfsinit(void)
+{
+ vn_create_cache();
+
+ /* Temporary, until we mount root */
+ rootdir = vn_alloc(KM_SLEEP);
+ rootdir->v_type = VDIR;
+}
+
+vfs_t *
+vfs_alloc(int kmflag)
+{
+ vfs_t *vfsp;
+
+ vfsp = kmem_alloc(sizeof (struct vfs), kmflag);
+
+ /*
+ * Do the simplest initialization here.
+ * Everything else gets done in vfs_init()
+ */
+ bzero(vfsp, sizeof (vfs_t));
+ return (vfsp);
+}
+
+void
+vfs_free(vfs_t *vfsp)
+{
+ /*
+ * One would be tempted to assert that "vfsp->vfs_count == 0".
+ * Don't. See fs/vfs.c
+ */
+
+ /* If FEM was in use, make sure everything gets cleaned up */
+
+ if (vfsp->vfs_implp)
+ vfsimpl_teardown(vfsp);
+ sema_destroy(&vfsp->vfs_reflock);
+ kmem_free(vfsp, sizeof (struct vfs));
+}
+
+/*
+ * Increments the vfs reference count by one atomically.
+ */
+void
+vfs_hold(vfs_t *vfsp)
+{
+ atomic_inc_32(&vfsp->vfs_count);
+ ASSERT(vfsp->vfs_count != 0);
+}
+
+/*
+ * Decrements the vfs reference count by one atomically. When
+ * vfs reference count becomes zero, it calls the file system
+ * specific vfs_freevfs() to free up the resources.
+ */
+void
+vfs_rele(vfs_t *vfsp)
+{
+ ASSERT(vfsp->vfs_count != 0);
+ if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) {
+ VFS_FREEVFS(vfsp);
+ // lofi_remove(vfsp);
+ // zone_rele_ref...
+ // vfs_freemnttab(vfsp);
+ vfs_free(vfsp);
+ }
+}
+
+/*
+ * Generic operations vector support.
+ */
+
+int
+fs_build_vector(void *vector, int *unused_ops,
+ const fs_operation_trans_def_t *translation,
+ const fs_operation_def_t *operations)
+{
+ int i, num_trans, num_ops, used;
+
+ /*
+ * Count the number of translations and the number of supplied
+ * operations.
+ */
+
+ {
+ const fs_operation_trans_def_t *p;
+
+ for (num_trans = 0, p = translation;
+ p->name != NULL;
+ num_trans++, p++)
+ ;
+ }
+
+ {
+ const fs_operation_def_t *p;
+
+ for (num_ops = 0, p = operations;
+ p->name != NULL;
+ num_ops++, p++)
+ ;
+ }
+
+ /* Walk through each operation known to our caller. There will be */
+ /* one entry in the supplied "translation table" for each. */
+
+ used = 0;
+
+ for (i = 0; i < num_trans; i++) {
+ int j, found;
+ char *curname;
+ fs_generic_func_p result;
+ fs_generic_func_p *location;
+
+ curname = translation[i].name;
+
+ /* Look for a matching operation in the list supplied by the */
+ /* file system. */
+
+ found = 0;
+
+ for (j = 0; j < num_ops; j++) {
+ if (strcmp(operations[j].name, curname) == 0) {
+ used++;
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * If the file system is using a "placeholder" for default
+ * or error functions, grab the appropriate function out of
+ * the translation table. If the file system didn't supply
+ * this operation at all, use the default function.
+ */
+
+ if (found) {
+ result = operations[j].func.fs_generic;
+ if (result == fs_default) {
+ result = translation[i].defaultFunc;
+ } else if (result == fs_error) {
+ result = translation[i].errorFunc;
+ } else if (result == NULL) {
+ /* Null values are PROHIBITED */
+ return (EINVAL);
+ }
+ } else {
+ result = translation[i].defaultFunc;
+ }
+
+ /* Now store the function into the operations vector. */
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ location = (fs_generic_func_p *)
+ (((char *)vector) + translation[i].offset);
+
+ *location = result;
+ }
+
+ *unused_ops = num_ops - used;
+
+ return (0);
+}
+
+/* Placeholder functions, should never be called. */
+
+int
+fs_error(void)
+{
+ cmn_err(CE_PANIC, "fs_error called");
+ return (0);
+}
+
+int
+fs_default(void)
+{
+ cmn_err(CE_PANIC, "fs_default called");
+ return (0);
+}
+
+// rootconf
+// getfsname
+// getrootfs
+
+/*
+ * VFS feature routines
+ */
+
+#define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF)
+#define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL)
+
+/* Register a feature in the vfs */
+void
+vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+
+ vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
+}
+
+void
+vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+ vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
+}
+
+/*
+ * Query a vfs for a feature.
+ * Returns 1 if feature is present, 0 if not
+ */
+int
+vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ int ret = 0;
+
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return (ret);
+
+ if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
+ ret = 1;
+
+ return (ret);
+}
+
+// vfs_propagate_features
+// vfs_get_lofi
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c
new file mode 100644
index 0000000000..07eb5bc18d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c
@@ -0,0 +1,2026 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * This file contains those functions from fs/vnode.c that can be
+ * used with relatively little change. Functions that differ
+ * significantly from that are in other files.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <fs/fs_subr.h>
+#include <fs/fs_reparse.h>
+
+#include <libfksmbfs.h>
+
+/* Determine if this vnode is a file that is read-only */
+#define ISROFILE(vp) \
+ ((vp)->v_type != VCHR && (vp)->v_type != VBLK && \
+ (vp)->v_type != VFIFO && vn_is_readonly(vp))
+
+#define VOPSTATS_UPDATE(vp, counter) ((void)vp)
+#define VOPSTATS_UPDATE_IO(vp, counter, bytecounter, bytesval) \
+ ((void)vp, (void)bytesval)
+#define VOPXID_MAP_CR(vp, cr) ((void)vp)
+
+/*
+ * Excerpts from fs/vnode.c
+ */
+
+/* Global used for empty/invalid v_path */
+char *vn_vpath_empty = "";
+
+static int fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr);
+
+/*
+ * Convert stat(2) formats to vnode types and vice versa. (Knows about
+ * numerical order of S_IFMT and vnode types.)
+ */
+enum vtype iftovt_tab[] = {
+ VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
+ VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
+};
+
+ushort_t vttoif_tab[] = {
+ 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
+ S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
+};
+
+/*
+ * The system vnode cache.
+ */
+
+kmem_cache_t *vn_cache;
+
+
+/*
+ * Vnode operations vector.
+ */
+
+static const fs_operation_trans_def_t vn_ops_table[] = {
+ VOPNAME_OPEN, offsetof(struct vnodeops, vop_open),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CLOSE, offsetof(struct vnodeops, vop_close),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READ, offsetof(struct vnodeops, vop_read),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_WRITE, offsetof(struct vnodeops, vop_write),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_IOCTL, offsetof(struct vnodeops, vop_ioctl),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SETFL, offsetof(struct vnodeops, vop_setfl),
+ fs_setfl, fs_nosys,
+
+ VOPNAME_GETATTR, offsetof(struct vnodeops, vop_getattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SETATTR, offsetof(struct vnodeops, vop_setattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_ACCESS, offsetof(struct vnodeops, vop_access),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_LOOKUP, offsetof(struct vnodeops, vop_lookup),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CREATE, offsetof(struct vnodeops, vop_create),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_REMOVE, offsetof(struct vnodeops, vop_remove),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_LINK, offsetof(struct vnodeops, vop_link),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RENAME, offsetof(struct vnodeops, vop_rename),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_MKDIR, offsetof(struct vnodeops, vop_mkdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RMDIR, offsetof(struct vnodeops, vop_rmdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READDIR, offsetof(struct vnodeops, vop_readdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SYMLINK, offsetof(struct vnodeops, vop_symlink),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READLINK, offsetof(struct vnodeops, vop_readlink),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_FSYNC, offsetof(struct vnodeops, vop_fsync),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_INACTIVE, offsetof(struct vnodeops, vop_inactive),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_FID, offsetof(struct vnodeops, vop_fid),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RWLOCK, offsetof(struct vnodeops, vop_rwlock),
+ fs_rwlock, fs_rwlock,
+
+ VOPNAME_RWUNLOCK, offsetof(struct vnodeops, vop_rwunlock),
+ (fs_generic_func_p) fs_rwunlock,
+ (fs_generic_func_p) fs_rwunlock, /* no errors allowed */
+
+ VOPNAME_SEEK, offsetof(struct vnodeops, vop_seek),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CMP, offsetof(struct vnodeops, vop_cmp),
+ fs_cmp, fs_cmp, /* no errors allowed */
+
+ VOPNAME_FRLOCK, offsetof(struct vnodeops, vop_frlock),
+ fs_frlock, fs_nosys,
+
+ VOPNAME_SPACE, offsetof(struct vnodeops, vop_space),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_REALVP, offsetof(struct vnodeops, vop_realvp),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_GETPAGE, offsetof(struct vnodeops, vop_getpage),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_PUTPAGE, offsetof(struct vnodeops, vop_putpage),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_MAP, offsetof(struct vnodeops, vop_map),
+ (fs_generic_func_p) fs_nosys_map,
+ (fs_generic_func_p) fs_nosys_map,
+
+ VOPNAME_ADDMAP, offsetof(struct vnodeops, vop_addmap),
+ (fs_generic_func_p) fs_nosys_addmap,
+ (fs_generic_func_p) fs_nosys_addmap,
+
+ VOPNAME_DELMAP, offsetof(struct vnodeops, vop_delmap),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_POLL, offsetof(struct vnodeops, vop_poll),
+ (fs_generic_func_p) fs_poll, (fs_generic_func_p) fs_nosys_poll,
+
+ VOPNAME_DUMP, offsetof(struct vnodeops, vop_dump),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_PATHCONF, offsetof(struct vnodeops, vop_pathconf),
+ fs_pathconf, fs_nosys,
+
+ VOPNAME_PAGEIO, offsetof(struct vnodeops, vop_pageio),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_DUMPCTL, offsetof(struct vnodeops, vop_dumpctl),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_DISPOSE, offsetof(struct vnodeops, vop_dispose),
+ (fs_generic_func_p) fs_dispose,
+ (fs_generic_func_p) fs_nodispose,
+
+ VOPNAME_SETSECATTR, offsetof(struct vnodeops, vop_setsecattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_GETSECATTR, offsetof(struct vnodeops, vop_getsecattr),
+ fs_fab_acl, fs_nosys,
+
+ VOPNAME_SHRLOCK, offsetof(struct vnodeops, vop_shrlock),
+ fs_shrlock, fs_nosys,
+
+ VOPNAME_VNEVENT, offsetof(struct vnodeops, vop_vnevent),
+ (fs_generic_func_p) fs_vnevent_nosupport,
+ (fs_generic_func_p) fs_vnevent_nosupport,
+
+ VOPNAME_REQZCBUF, offsetof(struct vnodeops, vop_reqzcbuf),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RETZCBUF, offsetof(struct vnodeops, vop_retzcbuf),
+ fs_nosys, fs_nosys,
+
+ NULL, 0, NULL, NULL
+};
+
+/* Extensible attribute (xva) routines. */
+
+/*
+ * Zero out the structure, set the size of the requested/returned bitmaps,
+ * set AT_XVATTR in the embedded vattr_t's va_mask, and set up the pointer
+ * to the returned attributes array.
+ */
+void
+xva_init(xvattr_t *xvap)
+{
+ bzero(xvap, sizeof (xvattr_t));
+ xvap->xva_mapsize = XVA_MAPSIZE;
+ xvap->xva_magic = XVA_MAGIC;
+ xvap->xva_vattr.va_mask = AT_XVATTR;
+ xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0];
+}
+
+/*
+ * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t
+ * structure. Otherwise, returns NULL.
+ */
+xoptattr_t *
+xva_getxoptattr(xvattr_t *xvap)
+{
+ xoptattr_t *xoap = NULL;
+ if (xvap->xva_vattr.va_mask & AT_XVATTR)
+ xoap = &xvap->xva_xoptattrs;
+ return (xoap);
+}
+
+// vska_compar
+// create_vopstats_template
+// new_vskstat
+// vopstats_startup
+// initialize_vopstats
+// get_fstype_vopstats
+// get_vskstat_anchor
+// teardown_vopstats
+
+/*
+ * Read or write a vnode. Called from kernel code.
+ */
+int
+vn_rdwr(
+ enum uio_rw rw,
+ struct vnode *vp,
+ caddr_t base,
+ ssize_t len,
+ offset_t offset,
+ enum uio_seg seg,
+ int ioflag,
+ rlim64_t ulimit, /* meaningful only if rw is UIO_WRITE */
+ cred_t *cr,
+ ssize_t *residp)
+{
+ struct uio uio;
+ struct iovec iov;
+ int error;
+ int in_crit = 0;
+
+ if (rw == UIO_WRITE && ISROFILE(vp))
+ return (EROFS);
+
+ if (len < 0)
+ return (EIO);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ iov.iov_base = base;
+ iov.iov_len = len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_loffset = offset;
+ uio.uio_segflg = (short)seg;
+ uio.uio_resid = len;
+ uio.uio_llimit = ulimit;
+
+ /*
+ * We have to enter the critical region before calling VOP_RWLOCK
+ * to avoid a deadlock with ufs.
+ */
+ if (nbl_need_check(vp)) {
+ int svmand;
+
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+ error = nbl_svmand(vp, cr, &svmand);
+ if (error != 0)
+ goto done;
+ if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
+ uio.uio_offset, uio.uio_resid, svmand, NULL)) {
+ error = EACCES;
+ goto done;
+ }
+ }
+
+ (void) VOP_RWLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
+ if (rw == UIO_WRITE) {
+ uio.uio_fmode = FWRITE;
+ uio.uio_extflg = UIO_COPY_DEFAULT;
+ error = VOP_WRITE(vp, &uio, ioflag, cr, NULL);
+ } else {
+ uio.uio_fmode = FREAD;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ error = VOP_READ(vp, &uio, ioflag, cr, NULL);
+ }
+ VOP_RWUNLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
+ if (residp)
+ *residp = uio.uio_resid;
+ else if (uio.uio_resid)
+ error = EIO;
+
+done:
+ if (in_crit)
+ nbl_end_crit(vp);
+ return (error);
+}
+
+/*
+ * Incremend the hold on a vnode
+ * (Real kernel uses a macro)
+ */
+void
+vn_hold(struct vnode *vp)
+{
+ mutex_enter(&vp->v_lock);
+ (vp)->v_count++;
+ mutex_exit(&vp->v_lock);
+}
+
+/*
+ * Release a vnode. Call VOP_INACTIVE on last reference or
+ * decrement reference count...
+ */
+void
+vn_rele(vnode_t *vp)
+{
+ VERIFY(vp->v_count > 0);
+ mutex_enter(&vp->v_lock);
+ if (vp->v_count == 1) {
+ mutex_exit(&vp->v_lock);
+ VOP_INACTIVE(vp, CRED(), NULL);
+ return;
+ }
+ VN_RELE_LOCKED(vp);
+ mutex_exit(&vp->v_lock);
+}
+
+// vn_rele_dnlc
+// vn_rele_stream
+// vn_rele_inactive
+// vn_rele_async
+// vn_open, vn_openat
+// vn_open_upgrade
+// vn_open_downgrade
+// vn_create, vn_createat
+// vn_link, vn_linkat
+// vn_rename, vn_renameat
+// vn_remove, vn_removeat
+
+
+/*
+ * Utility function to compare equality of vnodes.
+ * Compare the underlying real vnodes, if there are underlying vnodes.
+ * This is a more thorough comparison than the VN_CMP() macro provides.
+ */
+int
+vn_compare(vnode_t *vp1, vnode_t *vp2)
+{
+ vnode_t *realvp;
+
+ if (vp1 != NULL && VOP_REALVP(vp1, &realvp, NULL) == 0)
+ vp1 = realvp;
+ if (vp2 != NULL && VOP_REALVP(vp2, &realvp, NULL) == 0)
+ vp2 = realvp;
+ return (VN_CMP(vp1, vp2));
+}
+
+// vn_vfslocks_buckets
+// vn_vfslocks_getlock
+// vn_vfslocks_rele
+
+static krwlock_t vfsentry_ve_lock;
+
+/*
+ * vn_vfswlock_wait is used to implement a lock which is logically a
+ * writers lock protecting the v_vfsmountedhere field.
+ * vn_vfswlock_wait has been modified to be similar to vn_vfswlock,
+ * except that it blocks to acquire the lock VVFSLOCK.
+ *
+ * traverse() and routines re-implementing part of traverse (e.g. autofs)
+ * need to hold this lock. mount(), vn_rename(), vn_remove() and so on
+ * need the non-blocking version of the writers lock i.e. vn_vfswlock
+ */
+int
+vn_vfswlock_wait(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ rw_enter(&vfsentry_ve_lock, RW_WRITER);
+
+ return (0);
+}
+
+int
+vn_vfsrlock_wait(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ rw_enter(&vfsentry_ve_lock, RW_READER);
+
+ return (0);
+}
+
+/*
+ * vn_vfswlock is used to implement a lock which is logically a writers lock
+ * protecting the v_vfsmountedhere field.
+ */
+int
+vn_vfswlock(vnode_t *vp)
+{
+
+ if (vp == NULL)
+ return (EBUSY);
+
+ if (rw_tryenter(&vfsentry_ve_lock, RW_WRITER))
+ return (0);
+
+ return (EBUSY);
+}
+
+int
+vn_vfsrlock(vnode_t *vp)
+{
+
+ if (vp == NULL)
+ return (EBUSY);
+
+ if (rw_tryenter(&vfsentry_ve_lock, RW_READER))
+ return (0);
+
+ return (EBUSY);
+}
+
+void
+vn_vfsunlock(vnode_t *vp)
+{
+
+ rw_exit(&vfsentry_ve_lock);
+}
+
+int
+vn_vfswlock_held(vnode_t *vp)
+{
+ int held;
+
+ ASSERT(vp != NULL);
+
+ held = rw_write_held(&vfsentry_ve_lock);
+
+ return (held);
+}
+
+
+int
+vn_make_ops(
+ const char *name, /* Name of file system */
+ const fs_operation_def_t *templ, /* Operation specification */
+ vnodeops_t **actual) /* Return the vnodeops */
+{
+ int unused_ops;
+ int error;
+
+ *actual = (vnodeops_t *)kmem_alloc(sizeof (vnodeops_t), KM_SLEEP);
+
+ (*actual)->vnop_name = name;
+
+ error = fs_build_vector(*actual, &unused_ops, vn_ops_table, templ);
+ if (error) {
+ kmem_free(*actual, sizeof (vnodeops_t));
+ }
+
+#if DEBUG
+ if (unused_ops != 0)
+ cmn_err(CE_WARN, "vn_make_ops: %s: %d operations supplied "
+ "but not used", name, unused_ops);
+#endif
+
+ return (error);
+}
+
+/*
+ * Free the vnodeops created as a result of vn_make_ops()
+ */
+void
+vn_freevnodeops(vnodeops_t *vnops)
+{
+ kmem_free(vnops, sizeof (vnodeops_t));
+}
+
+/*
+ * Vnode cache.
+ */
+
+/* ARGSUSED */
+static int
+vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ struct vnode *vp = buf;
+
+ bzero(vp, sizeof (*vp));
+ mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
+ vp->v_path = vn_vpath_empty;
+ vp->v_fd = -1;
+ vp->v_st_dev = NODEV;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+vn_cache_destructor(void *buf, void *cdrarg)
+{
+ struct vnode *vp;
+
+ vp = buf;
+
+ rw_destroy(&vp->v_nbllock);
+ mutex_destroy(&vp->v_lock);
+}
+
+void
+vn_create_cache(void)
+{
+ vn_cache = kmem_cache_create("vn_cache", sizeof (struct vnode),
+ VNODE_ALIGN, vn_cache_constructor, vn_cache_destructor, NULL, NULL,
+ NULL, 0);
+}
+
+void
+vn_destroy_cache(void)
+{
+ kmem_cache_destroy(vn_cache);
+}
+
+/*
+ * Used by file systems when fs-specific nodes (e.g., ufs inodes) are
+ * cached by the file system and vnodes remain associated.
+ */
+void
+vn_recycle(vnode_t *vp)
+{
+ VERIFY(vp->v_path != NULL);
+
+ /*
+ * XXX - This really belongs in vn_reinit(), but we have some issues
+ * with the counts. Best to have it here for clean initialization.
+ */
+ vp->v_rdcnt = 0;
+ vp->v_wrcnt = 0;
+
+ /*
+ * If FEM was in use...
+ */
+
+ if (vp->v_path != vn_vpath_empty) {
+ kmem_free(vp->v_path, strlen(vp->v_path) + 1);
+ vp->v_path = vn_vpath_empty;
+ }
+ // vsd_free(vp);
+}
+
+/*
+ * Used to reset the vnode fields including those that are directly accessible
+ * as well as those which require an accessor function.
+ */
+void
+vn_reinit(vnode_t *vp)
+{
+ vp->v_count = 1;
+ // vp->v_count_dnlc = 0;
+ vp->v_vfsp = NULL;
+ vp->v_stream = NULL;
+ vp->v_vfsmountedhere = NULL;
+ vp->v_flag = 0;
+ vp->v_type = VNON;
+ vp->v_rdev = NODEV;
+
+ vp->v_xattrdir = NULL;
+
+ /*
+ * In a few specific instances, vn_reinit() is used to initialize
+ * locally defined vnode_t instances. Lacking the construction offered
+ * by vn_alloc(), these vnodes require v_path initialization.
+ */
+ if (vp->v_path == NULL) {
+ vp->v_path = vn_vpath_empty;
+ }
+
+ /* Handles v_femhead, v_path, and the r/w/map counts */
+ vn_recycle(vp);
+}
+
+vnode_t *
+vn_alloc(int kmflag)
+{
+ vnode_t *vp;
+
+ vp = kmem_cache_alloc(vn_cache, kmflag);
+
+ if (vp != NULL) {
+ // vp->v_femhead = NULL; /* Must be done before vn_reinit() */
+ // vp->v_fopdata = NULL;
+ vn_reinit(vp);
+ }
+
+ return (vp);
+}
+
+void
+vn_free(vnode_t *vp)
+{
+ extern vnode_t *rootdir;
+ ASSERT(vp != rootdir);
+
+ /*
+ * Some file systems call vn_free() with v_count of zero,
+ * some with v_count of 1. In any case, the value should
+ * never be anything else.
+ */
+ ASSERT((vp->v_count == 0) || (vp->v_count == 1));
+ VERIFY(vp->v_path != NULL);
+ if (vp->v_path != vn_vpath_empty) {
+ kmem_free(vp->v_path, strlen(vp->v_path) + 1);
+ vp->v_path = vn_vpath_empty;
+ }
+
+ /* If FEM was in use... */
+
+ // vsd_free(vp);
+ kmem_cache_free(vn_cache, vp);
+}
+
+/*
+ * vnode status changes, should define better states than 1, 0.
+ */
+void
+vn_reclaim(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_RECLAIMED);
+}
+
+void
+vn_idle(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_IDLED);
+}
+void
+vn_exists(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_EXISTS);
+}
+
+void
+vn_invalid(vnode_t *vp)
+{
+}
+
+/* Vnode event notification */
+// vnevent_support()
+// vnevent_...
+
+/*
+ * Vnode accessors.
+ */
+
+int
+vn_is_readonly(vnode_t *vp)
+{
+ return (vp->v_vfsp->vfs_flag & VFS_RDONLY);
+}
+
+int
+vn_has_flocks(vnode_t *vp)
+{
+ return (0);
+}
+
+int
+vn_has_mandatory_locks(vnode_t *vp, int mode)
+{
+ return (0);
+}
+
+int
+vn_has_cached_data(vnode_t *vp)
+{
+ return (0);
+}
+
+// vn_can_change_zones
+
+/*
+ * Return nonzero if the vnode is a mount point, zero if not.
+ */
+int
+vn_ismntpt(vnode_t *vp)
+{
+ return (vp->v_vfsmountedhere != NULL);
+}
+
+/* Retrieve the vfs (if any) mounted on this vnode */
+vfs_t *
+vn_mountedvfs(vnode_t *vp)
+{
+ return (vp->v_vfsmountedhere);
+}
+
+/*
+ * Return nonzero if the vnode is referenced by the dnlc, zero if not.
+ * (no DNLC here)
+ */
+int
+vn_in_dnlc(vnode_t *vp)
+{
+ return (0);
+}
+
+
+/*
+ * vn_has_other_opens() checks whether a particular file is opened by more than
+ * just the caller and whether the open is for read and/or write.
+ * This routine is for calling after the caller has already called VOP_OPEN()
+ * and the caller wishes to know if they are the only one with it open for
+ * the mode(s) specified.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_has_other_opens(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt > 1)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt > 1)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
+ * vn_is_opened() checks whether a particular file is opened and
+ * whether the open is for read and/or write.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_is_opened(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if (vp->v_rdcnt && vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if (vp->v_rdcnt || vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
+ * vn_is_mapped() checks whether a particular file is mapped and whether
+ * the file is mapped read and/or write. (no mmap here)
+ */
+int
+vn_is_mapped(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+ return (V_FALSE);
+}
+
+/*
+ * Set the operations vector for a vnode.
+ */
+void
+vn_setops(vnode_t *vp, vnodeops_t *vnodeops)
+{
+
+ ASSERT(vp != NULL);
+ ASSERT(vnodeops != NULL);
+
+ vp->v_op = vnodeops;
+}
+
+/*
+ * Retrieve the operations vector for a vnode
+ */
+vnodeops_t *
+vn_getops(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ return (vp->v_op);
+}
+
+/*
+ * Returns non-zero (1) if the vnodeops matches that of the vnode.
+ * Returns zero (0) if not.
+ */
+int
+vn_matchops(vnode_t *vp, vnodeops_t *vnodeops)
+{
+ return (vn_getops(vp) == vnodeops);
+}
+
+// vn_matchopval
+// fs_new_caller_id
+
+// vn_clearpath
+// vn_setpath_common
+
+/* ARGSUSED */
+void
+vn_updatepath(vnode_t *pvp, vnode_t *vp, const char *name)
+{
+}
+
+// vn_setpath...
+// vn_renamepath
+// vn_copypath
+
+// vn_vmpss_usepageio
+
+/* VOP_XXX() macros call the corresponding fop_xxx() function */
+
+int
+fop_open(
+ vnode_t **vpp,
+ int mode,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int ret;
+ vnode_t *vp = *vpp;
+
+ VN_HOLD(vp);
+ /*
+ * Adding to the vnode counts before calling open
+ * avoids the need for a mutex...
+ */
+ if ((*vpp)->v_type == VREG) {
+ if (mode & FREAD)
+ atomic_inc_32(&(*vpp)->v_rdcnt);
+ if (mode & FWRITE)
+ atomic_inc_32(&(*vpp)->v_wrcnt);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
+
+ if (ret) {
+ /*
+ * Use the saved vp just in case the vnode ptr got trashed
+ * by the error.
+ */
+ VOPSTATS_UPDATE(vp, open);
+ if ((vp->v_type == VREG) && (mode & FREAD))
+ atomic_dec_32(&vp->v_rdcnt);
+ if ((vp->v_type == VREG) && (mode & FWRITE))
+ atomic_dec_32(&vp->v_wrcnt);
+ } else {
+ /*
+ * Some filesystems will return a different vnode,
+ * but the same path was still used to open it.
+ * So if we do change the vnode and need to
+ * copy over the path, do so here, rather than special
+ * casing each filesystem. Adjust the vnode counts to
+ * reflect the vnode switch.
+ */
+ VOPSTATS_UPDATE(*vpp, open);
+ if (*vpp != vp && *vpp != NULL) {
+ // vn_copypath(vp, *vpp);
+ if (((*vpp)->v_type == VREG) && (mode & FREAD))
+ atomic_inc_32(&(*vpp)->v_rdcnt);
+ if ((vp->v_type == VREG) && (mode & FREAD))
+ atomic_dec_32(&vp->v_rdcnt);
+ if (((*vpp)->v_type == VREG) && (mode & FWRITE))
+ atomic_inc_32(&(*vpp)->v_wrcnt);
+ if ((vp->v_type == VREG) && (mode & FWRITE))
+ atomic_dec_32(&vp->v_wrcnt);
+ }
+ }
+ VN_RELE(vp);
+ return (ret);
+}
+
+int
+fop_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
+ VOPSTATS_UPDATE(vp, close);
+ /*
+ * Check passed in count to handle possible dups. Vnode counts are only
+ * kept on regular files
+ */
+ if ((vp->v_type == VREG) && (count == 1)) {
+ if (flag & FREAD) {
+ ASSERT(vp->v_rdcnt > 0);
+ atomic_dec_32(&vp->v_rdcnt);
+ }
+ if (flag & FWRITE) {
+ ASSERT(vp->v_wrcnt > 0);
+ atomic_dec_32(&vp->v_wrcnt);
+ }
+ }
+ return (err);
+}
+
+int
+fop_read(
+ vnode_t *vp,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
+ VOPSTATS_UPDATE_IO(vp, read,
+ read_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_write(
+ vnode_t *vp,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_write)(vp, uiop, ioflag, cr, ct);
+ VOPSTATS_UPDATE_IO(vp, write,
+ write_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp, ct);
+ VOPSTATS_UPDATE(vp, ioctl);
+ return (err);
+}
+
+int
+fop_setfl(
+ vnode_t *vp,
+ int oflags,
+ int nflags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr, ct);
+ VOPSTATS_UPDATE(vp, setfl);
+ return (err);
+}
+
+int
+fop_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, getattr);
+ return (err);
+}
+
+int
+fop_setattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, setattr);
+ return (err);
+}
+
+int
+fop_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ if ((flags & V_ACE_MASK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, access);
+ return (err);
+}
+
+int
+fop_lookup(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t **vpp,
+ pathname_t *pnp,
+ int flags,
+ vnode_t *rdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int *deflags, /* Returned per-dirent flags */
+ pathname_t *ppnp) /* Returned case-preserved name in directory */
+{
+ int ret;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly. It is required
+ * that if the vfs supports case-insensitive lookup, it also
+ * supports extended dirent flags.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ /*
+ * The real vnode.c would call xattr_dir_lookup here,
+ * which inserts the special "System Attribute" files:
+ * (SUNWattr_rw, SUNWattr_ro) into the xattr list.
+ * Here the main focus is on testing xattr support,
+ * so the system attribute stuff is ommitted.
+ */
+#if 0
+ if ((flags & LOOKUP_XATTR) && (flags & LOOKUP_HAVE_SYSATTR_DIR) == 0) {
+ // Don't need xattr support in libfksmbfs.
+ // ret = xattr_dir_lookup(dvp, vpp, flags, cr);
+ ret = EINVAL;
+ } else
+#endif
+ {
+ ret = (*(dvp)->v_op->vop_lookup)
+ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
+ }
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, lookup);
+ vn_updatepath(dvp, *vpp, nm);
+ }
+
+ return (ret);
+}
+
+int
+fop_create(
+ vnode_t *dvp,
+ char *name,
+ vattr_t *vap,
+ vcexcl_t excl,
+ int mode,
+ vnode_t **vpp,
+ cred_t *cr,
+ int flags,
+ caller_context_t *ct,
+ vsecattr_t *vsecp) /* ACL to set during create */
+{
+ int ret;
+
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ ret = (*(dvp)->v_op->vop_create)
+ (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, create);
+ vn_updatepath(dvp, *vpp, name);
+ }
+
+ return (ret);
+}
+
+int
+fop_remove(
+ vnode_t *dvp,
+ char *nm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, remove);
+ return (err);
+}
+
+int
+fop_link(
+ vnode_t *tdvp,
+ vnode_t *svp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If the target file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(tdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(tdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(tdvp, cr);
+
+ err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
+ VOPSTATS_UPDATE(tdvp, link);
+ return (err);
+}
+
+int
+fop_rename(
+ vnode_t *sdvp,
+ char *snm,
+ vnode_t *tdvp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If the file system involved does not support
+ * case-insensitive access and said access is requested, fail
+ * quickly.
+ */
+ if (flags & FIGNORECASE &&
+ ((vfs_has_feature(sdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(sdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(tdvp, cr);
+
+ err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr, ct, flags);
+ VOPSTATS_UPDATE(sdvp, rename);
+ return (err);
+}
+
+int
+fop_mkdir(
+ vnode_t *dvp,
+ char *dirname,
+ vattr_t *vap,
+ vnode_t **vpp,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp) /* ACL to set during create */
+{
+ int ret;
+
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ ret = (*(dvp)->v_op->vop_mkdir)
+ (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, mkdir);
+ vn_updatepath(dvp, *vpp, dirname);
+ }
+
+ return (ret);
+}
+
+int
+fop_rmdir(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t *cdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, rmdir);
+ return (err);
+}
+
+int
+fop_readdir(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cr,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ /*
+ * If this file system doesn't support retrieving directory
+ * entry flags and said access is requested, fail quickly.
+ */
+ if (flags & V_RDDIR_ENTFLAGS &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS) == 0)
+ return (EINVAL);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp, ct, flags);
+ VOPSTATS_UPDATE_IO(vp, readdir,
+ readdir_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_symlink(
+ vnode_t *dvp,
+ char *linkname,
+ vattr_t *vap,
+ char *target,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+ xvattr_t xvattr;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ /* check for reparse point */
+ if ((vfs_has_feature(dvp->v_vfsp, VFSFT_REPARSE)) &&
+ (strncmp(target, FS_REPARSE_TAG_STR,
+ strlen(FS_REPARSE_TAG_STR)) == 0)) {
+ if (!fs_reparse_mark(target, vap, &xvattr))
+ vap = (vattr_t *)&xvattr;
+ }
+
+ err = (*(dvp)->v_op->vop_symlink)
+ (dvp, linkname, vap, target, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, symlink);
+ return (err);
+}
+
+int
+fop_readlink(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr, ct);
+ VOPSTATS_UPDATE(vp, readlink);
+ return (err);
+}
+
+int
+fop_fsync(
+ vnode_t *vp,
+ int syncflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr, ct);
+ VOPSTATS_UPDATE(vp, fsync);
+ return (err);
+}
+
+void
+fop_inactive(
+ vnode_t *vp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ /* Need to update stats before vop call since we may lose the vnode */
+ VOPSTATS_UPDATE(vp, inactive);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ (*(vp)->v_op->vop_inactive)(vp, cr, ct);
+}
+
+int
+fop_fid(
+ vnode_t *vp,
+ fid_t *fidp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_fid)(vp, fidp, ct);
+ VOPSTATS_UPDATE(vp, fid);
+ return (err);
+}
+
+int
+fop_rwlock(
+ vnode_t *vp,
+ int write_lock,
+ caller_context_t *ct)
+{
+ int ret;
+
+ ret = ((*(vp)->v_op->vop_rwlock)(vp, write_lock, ct));
+ VOPSTATS_UPDATE(vp, rwlock);
+ return (ret);
+}
+
+void
+fop_rwunlock(
+ vnode_t *vp,
+ int write_lock,
+ caller_context_t *ct)
+{
+ (*(vp)->v_op->vop_rwunlock)(vp, write_lock, ct);
+ VOPSTATS_UPDATE(vp, rwunlock);
+}
+
+int
+fop_seek(
+ vnode_t *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp, ct);
+ VOPSTATS_UPDATE(vp, seek);
+ return (err);
+}
+
+int
+fop_cmp(
+ vnode_t *vp1,
+ vnode_t *vp2,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp1)->v_op->vop_cmp)(vp1, vp2, ct);
+ VOPSTATS_UPDATE(vp1, cmp);
+ return (err);
+}
+
+int
+fop_frlock(
+ vnode_t *vp,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ struct flk_callback *flk_cbp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_frlock)
+ (vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
+ VOPSTATS_UPDATE(vp, frlock);
+ return (err);
+}
+
+int
+fop_space(
+ vnode_t *vp,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_space)(vp, cmd, bfp, flag, offset, cr, ct);
+ VOPSTATS_UPDATE(vp, space);
+ return (err);
+}
+
+int
+fop_realvp(
+ vnode_t *vp,
+ vnode_t **vpp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_realvp)(vp, vpp, ct);
+ VOPSTATS_UPDATE(vp, realvp);
+ return (err);
+}
+
+int
+fop_getpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ uint_t *protp,
+ page_t **plarr,
+ size_t plsz,
+ struct seg *seg,
+ caddr_t addr,
+ enum seg_rw rw,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_getpage)
+ (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr, ct);
+ VOPSTATS_UPDATE(vp, getpage);
+ return (err);
+}
+
+int
+fop_putpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, putpage);
+ return (err);
+}
+
+int
+fop_map(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t *addrp,
+ size_t len,
+ uchar_t prot,
+ uchar_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_map)
+ (vp, off, as, addrp, len, prot, maxprot, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, map);
+ return (err);
+}
+
+int
+fop_addmap(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uchar_t prot,
+ uchar_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ error = (*(vp)->v_op->vop_addmap)
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
+
+ VOPSTATS_UPDATE(vp, addmap);
+ return (error);
+}
+
+int
+fop_delmap(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint_t prot,
+ uint_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ error = (*(vp)->v_op->vop_delmap)
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
+
+ VOPSTATS_UPDATE(vp, delmap);
+ return (error);
+}
+
+
+int
+fop_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ struct pollhead **phpp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp, ct);
+ VOPSTATS_UPDATE(vp, poll);
+ return (err);
+}
+
+int
+fop_dump(
+ vnode_t *vp,
+ caddr_t addr,
+ offset_t lbdn,
+ offset_t dblks,
+ caller_context_t *ct)
+{
+ int err;
+
+ /* ensure lbdn and dblks can be passed safely to bdev_dump */
+ if ((lbdn != (daddr_t)lbdn) || (dblks != (int)dblks))
+ return (EIO);
+
+ err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks, ct);
+ VOPSTATS_UPDATE(vp, dump);
+ return (err);
+}
+
+int
+fop_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr, ct);
+ VOPSTATS_UPDATE(vp, pathconf);
+ return (err);
+}
+
+int
+fop_pageio(
+ vnode_t *vp,
+ struct page *pp,
+ u_offset_t io_off,
+ size_t io_len,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, pageio);
+ return (err);
+}
+
+int
+fop_dumpctl(
+ vnode_t *vp,
+ int action,
+ offset_t *blkp,
+ caller_context_t *ct)
+{
+ int err;
+ err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp, ct);
+ VOPSTATS_UPDATE(vp, dumpctl);
+ return (err);
+}
+
+void
+fop_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int flag,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ /* Must do stats first since it's possible to lose the vnode */
+ VOPSTATS_UPDATE(vp, dispose);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr, ct);
+}
+
+int
+fop_setsecattr(
+ vnode_t *vp,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, setsecattr);
+ return (err);
+}
+
+int
+fop_getsecattr(
+ vnode_t *vp,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, getsecattr);
+ return (err);
+}
+
+int
+fop_shrlock(
+ vnode_t *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, shrlock);
+ return (err);
+}
+
+int
+fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm, ct);
+ VOPSTATS_UPDATE(vp, vnevent);
+ return (err);
+}
+
+// fop_reqzcbuf
+// fop_retzcbuf
+
+// vsd_defaultdestructor
+// vsd_create, vsd_destroy
+// vsd_get, vsd_set
+// vsd_free, vsd_realloc
+
+static int
+fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
+{
+ return (-1);
+}
+
+/*
+ * Function to check whether a symlink is a reparse point.
+ * Return B_TRUE if it is a reparse point, else return B_FALSE
+ */
+boolean_t
+vn_is_reparse(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ xvattr_t xvattr;
+ xoptattr_t *xoap;
+
+ if ((vp->v_type != VLNK) ||
+ !(vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR)))
+ return (B_FALSE);
+
+ xva_init(&xvattr);
+ xoap = xva_getxoptattr(&xvattr);
+ ASSERT(xoap);
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+
+ if (VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct))
+ return (B_FALSE);
+
+ if ((!(xvattr.xva_vattr.va_mask & AT_XVATTR)) ||
+ (!(XVA_ISSET_RTN(&xvattr, XAT_REPARSE))))
+ return (B_FALSE);
+
+ return (xoap->xoa_reparse ? B_TRUE : B_FALSE);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c
new file mode 100644
index 0000000000..5593a8d542
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Simulating just one zone here (the global zone)
+ */
+
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <sys/debug.h>
+
+static void *zone_specific_val;
+static void *(*zkey_create)(zoneid_t);
+// static void (*zkey_shutdown)(zoneid_t, void *);
+// static void (*zkey_destroy)(zoneid_t, void *);
+
+/* ARGSUSED */
+void
+zone_key_create(zone_key_t *keyp, void *(*create)(zoneid_t),
+ void (*shutdown)(zoneid_t, void *), void (*destroy)(zoneid_t, void *))
+{
+
+ zkey_create = create;
+ // zkey_shutdown = shutdown;
+ // zkey_destroy = destroy;
+ *keyp = 1;
+}
+
+/* ARGSUSED */
+int
+zone_key_delete(zone_key_t key)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+zone_setspecific(zone_key_t key, zone_t *zone, const void *data)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+void *
+zone_getspecific(zone_key_t key, zone_t *zone)
+{
+ ASSERT(key == 1);
+ if (zone_specific_val == NULL)
+ zone_specific_val = (*zkey_create)(zone->zone_id);
+ return (zone_specific_val);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c b/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c
new file mode 100644
index 0000000000..ee92e3ed67
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c
@@ -0,0 +1,235 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
+ * All rights reserved.
+ */
+
+/*
+ * A homegrown reader/writer lock implementation. It addresses
+ * two requirements not addressed by the system primitives. They
+ * are that the `enter" operation is optionally interruptible and
+ * that that they can be re`enter'ed by writers without deadlock.
+ *
+ * All of this was borrowed from NFS.
+ * See: uts/common/fs/nfs/nfs_subr.c
+ *
+ * XXX: Could we make this serve our needs instead?
+ * See: uts/common/os/rwstlock.c
+ * (and then use it for NFS too)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Only can return non-zero if intr != 0.
+ */
+int
+smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr)
+{
+
+ mutex_enter(&l->lock);
+
+ /*
+ * If this is a nested enter, then allow it. There
+ * must be as many exits as enters through.
+ */
+ if (l->owner == curthread) {
+ /* lock is held for writing by current thread */
+ ASSERT(rw == RW_READER || rw == RW_WRITER);
+ l->count--;
+ } else if (rw == RW_READER) {
+ /*
+ * While there is a writer active or writers waiting,
+ * then wait for them to finish up and move on. Then,
+ * increment the count to indicate that a reader is
+ * active.
+ */
+ while (l->count < 0 || l->waiters > 0) {
+ if (intr) {
+ // lwp_nostop stuff...
+ (void) cv_wait_sig(&l->cv, &l->lock);
+ } else
+ cv_wait(&l->cv, &l->lock);
+ }
+ ASSERT(l->count < INT_MAX);
+#ifdef SMBDEBUG
+ if ((l->count % 10000) == 9999)
+ cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on"
+ "rwlock @ %p\n", l->count, (void *)&l);
+#endif
+ l->count++;
+ } else {
+ ASSERT(rw == RW_WRITER);
+ /*
+ * While there are readers active or a writer
+ * active, then wait for all of the readers
+ * to finish or for the writer to finish.
+ * Then, set the owner field to curthread and
+ * decrement count to indicate that a writer
+ * is active.
+ */
+ while (l->count > 0 || l->owner != NULL) {
+ l->waiters++;
+ if (intr) {
+ // lwp_nostop stuff...
+ if (!cv_wait_sig(&l->cv, &l->lock)) {
+ l->waiters--;
+ cv_broadcast(&l->cv);
+ mutex_exit(&l->lock);
+ return (EINTR);
+ }
+ } else
+ cv_wait(&l->cv, &l->lock);
+ l->waiters--;
+ }
+ l->owner = curthread;
+ l->count--;
+ }
+
+ mutex_exit(&l->lock);
+
+ return (0);
+}
+
+/*
+ * If the lock is available, obtain it and return non-zero. If there is
+ * already a conflicting lock, return 0 immediately.
+ */
+
+int
+smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw)
+{
+ mutex_enter(&l->lock);
+
+ /*
+ * If this is a nested enter, then allow it. There
+ * must be as many exits as enters through.
+ */
+ if (l->owner == curthread) {
+ /* lock is held for writing by current thread */
+ ASSERT(rw == RW_READER || rw == RW_WRITER);
+ l->count--;
+ } else if (rw == RW_READER) {
+ /*
+ * If there is a writer active or writers waiting, deny the
+ * lock. Otherwise, bump the count of readers.
+ */
+ if (l->count < 0 || l->waiters > 0) {
+ mutex_exit(&l->lock);
+ return (0);
+ }
+ l->count++;
+ } else {
+ ASSERT(rw == RW_WRITER);
+ /*
+ * If there are readers active or a writer active, deny the
+ * lock. Otherwise, set the owner field to curthread and
+ * decrement count to indicate that a writer is active.
+ */
+ if (l->count > 0 || l->owner != NULL) {
+ mutex_exit(&l->lock);
+ return (0);
+ }
+ l->owner = curthread;
+ l->count--;
+ }
+
+ mutex_exit(&l->lock);
+
+ return (1);
+}
+
+void
+smbfs_rw_exit(smbfs_rwlock_t *l)
+{
+
+ mutex_enter(&l->lock);
+ /*
+ * If this is releasing a writer lock, then increment count to
+ * indicate that there is one less writer active. If this was
+ * the last of possibly nested writer locks, then clear the owner
+ * field as well to indicate that there is no writer active
+ * and wakeup any possible waiting writers or readers.
+ *
+ * If releasing a reader lock, then just decrement count to
+ * indicate that there is one less reader active. If this was
+ * the last active reader and there are writer(s) waiting,
+ * then wake up the first.
+ */
+ if (l->owner != NULL) {
+ ASSERT(l->owner == curthread);
+ l->count++;
+ if (l->count == 0) {
+ l->owner = NULL;
+ cv_broadcast(&l->cv);
+ }
+ } else {
+ ASSERT(l->count > 0);
+ l->count--;
+ if (l->count == 0 && l->waiters > 0)
+ cv_broadcast(&l->cv);
+ }
+ mutex_exit(&l->lock);
+}
+
+int
+smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw)
+{
+
+ if (rw == RW_READER)
+ return (l->count > 0);
+ ASSERT(rw == RW_WRITER);
+ return (l->count < 0);
+}
+
+/* ARGSUSED */
+void
+smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
+{
+
+ l->count = 0;
+ l->waiters = 0;
+ l->owner = NULL;
+ mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+smbfs_rw_destroy(smbfs_rwlock_t *l)
+{
+
+ mutex_destroy(&l->lock);
+ cv_destroy(&l->cv);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h b/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h
new file mode 100644
index 0000000000..e168b008af
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _LIBFKSMBFS_H_
+#define _LIBFKSMBFS_H_
+
+/*
+ * Declarations for exports in fake_vfs.c
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+
+#ifndef MAXOFF32_T
+#define MAXOFF32_T 0x7fffffff
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Need these visible outside _FAKE_KERNEL for the test CLI.
+ * In the kmod/lib build these duplicate declarations in vfs.h or
+ * vnode.h but that's OK as long as the declarations are identical.
+ */
+struct mounta;
+struct stat64;
+int fake_installfs(vfsdef_t *);
+int fake_removefs(vfsdef_t *);
+int fake_domount(char *, struct mounta *, struct vfs **);
+int fake_dounmount(struct vfs *, int);
+int fake_lookup(vnode_t *, char *, vnode_t **);
+int fake_lookup_dir(char *, vnode_t **, char **);
+int fake_stat(vnode_t *, struct stat64 *, int);
+int fake_getdents(vnode_t *, offset_t *, void *, size_t);
+ssize_t fake_pread(vnode_t *, void *, size_t, off_t);
+ssize_t fake_pwrite(vnode_t *, void *, size_t, off_t);
+int fake_unlink(char *, int);
+int fake_rename(char *, char *);
+
+int vn_close_rele(vnode_t *vp, int flag);
+int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy, mode_t umask);
+int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask);
+
+void vn_rele(struct vnode *vp);
+
+/* In the real smbfs, these are _init(), _fini() */
+int fksmbfs_init(void);
+int fksmbfs_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFKSMBFS_H_ */
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs b/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs
new file mode 100644
index 0000000000..6e7f55f31d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfksmbfs.h>
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers b/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers
new file mode 100644
index 0000000000..6e8b11a4ef
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ fake_domount;
+ fake_dounmount;
+ fake_lookup;
+ fake_lookup_dir;
+ fake_getdents;
+ fake_pread;
+ fake_pwrite;
+ fake_rename;
+ fake_stat;
+ fake_unlink;
+
+ fksmbfs_fini;
+ fksmbfs_init;
+
+ fsop_root;
+ fsop_statfs;
+ fsop_sync;
+
+ vn_close_rele;
+ vn_create;
+ vn_open;
+ vn_rele;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile b/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile
new file mode 100644
index 0000000000..6e1eb18522
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbfs
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile b/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile
new file mode 100644
index 0000000000..6e1eb18522
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbfs
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile b/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile
new file mode 100644
index 0000000000..151660294b
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbfs/$(MACH64)
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
index 7524e2db55..b6b669cd27 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -36,7 +36,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/smbinfo.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/ntlocale.h>
#include <smbsrv/string.h>
#include <lsalib.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
index 956fbbad15..942650545f 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -41,7 +41,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/libmlsvc.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/smbinfo.h>
#include <smbsrv/netrauth.h>
#include <libsmbrdr.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
index 8b0c4e3fbd..edf6952a8d 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -37,7 +37,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <lsalib.h>
#include <samlib.h>
@@ -47,8 +47,8 @@
#define letohl(x) ((uint32_t)(x))
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
/* little-endian values on big-endian (swap) */
-#define letohl(x) BSWAP_32(x)
-#define htolel(x) BSWAP_32(x)
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
#endif /* (BYTE_ORDER == LITTLE_ENDIAN) */
/*
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
index dd15469c15..38dc21b712 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -48,7 +48,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/smbinfo.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/smb_sid.h>
#include <samlib.h>
diff --git a/usr/src/man/man3lib/libproc.3lib b/usr/src/man/man3lib/libproc.3lib
index 15b69e52d4..94ddc8b558 100644
--- a/usr/src/man/man3lib/libproc.3lib
+++ b/usr/src/man/man3lib/libproc.3lib
@@ -10,8 +10,10 @@
.\"
.\"
.\" Copyright 2018 Joyent, Inc.
+.\" Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+.\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
.\"
-.Dd September 15, 2018
+.Dd February 22, 2019
.Dt LIBPROC 3LIB
.Os
.Sh NAME
@@ -306,19 +308,19 @@ library.
.It Sy Perror_printf Ta Sy proc_arg_grab
.It Sy proc_arg_psinfo Ta Sy proc_arg_xgrab
.It Sy proc_arg_xpsinfo Ta Sy proc_content2str
-.It Sy proc_finistdio Ta Sy proc_fltname
-.It Sy proc_fltset2str Ta Sy proc_flushstdio
-.It Sy proc_get_auxv Ta Sy proc_get_cred
-.It Sy proc_get_priv Ta Sy proc_get_psinfo
-.It Sy proc_get_status Ta Sy proc_initstdio
-.It Sy proc_lwp_in_set Ta Sy proc_lwp_range_valid
-.It Sy proc_signame Ta Sy proc_sigset2str
-.It Sy proc_str2content Ta Sy proc_str2flt
-.It Sy proc_str2fltset Ta Sy proc_str2sig
-.It Sy proc_str2sigset Ta Sy proc_str2sys
-.It Sy proc_str2sysset Ta Sy proc_sysname
-.It Sy proc_sysset2str Ta Sy proc_unctrl_psinfo
-.It Sy proc_walk Ta ""
+.It Sy proc_dmodelname Ta Sy proc_finistdio
+.It Sy proc_fltname Ta Sy proc_fltset2str
+.It Sy proc_flushstdio Ta Sy proc_proc_get_auxv
+.It Sy proc_get_cred Ta Sy proc_get_priv
+.It Sy proc_get_psinfo Ta Sy proc_get_status
+.It Sy proc_get_initstdio Ta Sy proc_lwp_in_set
+.It Sy proc_lwp_range_valid Ta Sy proc_signame
+.It Sy proc_sigset2str Ta Sy proc_str2content
+.It Sy proc_str2flt Ta Sy proc_str2fltset
+.It Sy proc_str2sig Ta Sy proc_str2sigset
+.It Sy proc_str2sys Ta Sy proc_str2sysset
+.It Sy proc_sysname Ta Sy proc_sysset2str
+.It Sy proc_unctrl_psinfo Ta ""
.El
.Ss x86 Specific Routines
The following routines are specific to the x86, 32-bit and 64-bit,
@@ -1218,6 +1220,7 @@ changes may occur which break both source and binary compatibility.
.Xr proc_arg_xgrab 3PROC ,
.Xr proc_arg_xpsinfo 3PROC ,
.Xr proc_content2str 3PROC ,
+.Xr proc_dmodelname 3PROC ,
.Xr proc_finistdio 3PROC ,
.Xr proc_fltname 3PROC ,
.Xr proc_fltset2str 3PROC ,
diff --git a/usr/src/man/man3proc/Makefile b/usr/src/man/man3proc/Makefile
index e59e81fbf3..00403a19fa 100644
--- a/usr/src/man/man3proc/Makefile
+++ b/usr/src/man/man3proc/Makefile
@@ -13,7 +13,8 @@
# Copyright 2011, Richard Lowe
# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
-#
+# Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
include $(SRC)/Makefile.master
@@ -220,6 +221,7 @@ MANLINKS= \
Pread_string.3proc \
proc_arg_xgrab.3proc \
proc_arg_xpsinfo.3proc \
+ proc_dmodelname.3proc \
proc_finistdio.3proc \
proc_flushstdio.3proc \
proc_free_priv.3proc \
@@ -395,6 +397,7 @@ proc_str2content.3proc := LINKSRC = proc_content2str.3proc
proc_flushstdio.3proc := LINKSRC = proc_initstdio.3proc
proc_finistdio.3proc := LINKSRC = proc_initstdio.3proc
+proc_dmodelname.3proc := LINKSRC = proc_fltname.3proc
proc_signame.3proc := LINKSRC = proc_fltname.3proc
proc_sysname.3proc := LINKSRC = proc_fltname.3proc
diff --git a/usr/src/man/man3proc/proc_fltname.3proc b/usr/src/man/man3proc/proc_fltname.3proc
index 1dc563b714..f3f4a45aa0 100644
--- a/usr/src/man/man3proc/proc_fltname.3proc
+++ b/usr/src/man/man3proc/proc_fltname.3proc
@@ -10,6 +10,8 @@
.\"
.\"
.\" Copyright 2015 Joyent, Inc.
+.\" Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+.\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
.\"
.Dd May 11, 2016
.Dt PROC_FLTNAME 3PROC
@@ -17,8 +19,9 @@
.Sh NAME
.Nm proc_fltname ,
.Nm proc_signame ,
-.Nm proc_sysname
-.Nd convert a fault, signal, and system call to a name
+.Nm proc_sysname ,
+.Nm proc_dmodelname
+.Nd convert a fault, signal, system call and data model to a name
.Sh SYNOPSIS
.Lb libproc
.In libproc.h
@@ -40,17 +43,25 @@
.Fa "char *buf"
.Fa "size_t bufsz"
.Fc
+.Ft "char *"
+.Fo proc_dmodelname
+.Fa "int dmodel"
+.Fa "char *buf"
+.Fa "size_t bufsz"
+.Fc
.Sh DESCRIPTION
The
.Fn proc_fltname ,
.Fn proc_signame ,
-and
.Fn proc_sysname
-functions respectively convert the fault, signal, and system call in
+and
+.Fn proc_dmodelname
+functions respectively convert the fault, signal, system call and data model in
.Fa flt ,
.Fa sig ,
-and
.Fa sys
+and
+.Fa dmodel
to a human-readable name and place the corresponding string in
.Fa buf .
Up to
@@ -61,8 +72,9 @@ characters, including the null terminator, will be written into
Upon successful completion, the
.Fn proc_fltname ,
.Fn proc_signame ,
-and
.Fn proc_sysname
+and
+.Fn proc_dmodelname
functions return a pointer to
.Fa buf .
The contents of
diff --git a/usr/src/man/man4/nsmbrc.4 b/usr/src/man/man4/nsmbrc.4
index 2468be8f28..5eaffa9f63 100644
--- a/usr/src/man/man4/nsmbrc.4
+++ b/usr/src/man/man4/nsmbrc.4
@@ -3,7 +3,8 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH NSMBRC 4 "Dec 8, 2008"
+.\" Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+.TH NSMBRC 4 "May 8, 2018"
.SH NAME
nsmbrc \- configuration file for Solaris CIFS client requests
.SH SYNOPSIS
@@ -13,7 +14,6 @@ nsmbrc \- configuration file for Solaris CIFS client requests
.fi
.SH DESCRIPTION
-.sp
.LP
Global behavior of the Solaris CIFS client is defined by property values that
are stored in the Service Management Facility (SMF). The \fB\&.nsmbrc\fR file
@@ -137,6 +137,32 @@ value is \fBntlm\fR.
.sp
.ne 2
.na
+\fB\fBmin_protocol\fR\fR
+.ad
+.sp .6
+.RS 4n
+Is the minimum SMB protocol level that will be negotiated,
+which must be one of: \fB1\fR, \fB2.1\fR
+This property can only be set in the default and server sections.
+The default value is \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmax_protocol\fR\fR
+.ad
+.sp .6
+.RS 4n
+Is the maximum SMB protocol level that will be negotiated,
+which must be one of: \fB1\fR, \fB2.1\fR
+This property can only be set in the default and server sections.
+The default value is \fB2.1\fR.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBnbns\fR\fR
.ad
.sp .6
@@ -254,7 +280,6 @@ property. Use the \fBdomain\fR property instead.
.RE
.SH EXAMPLES
-.sp
.LP
The examples in this section show how to use the \fB\&.nsmbrc\fR file and the
\fBsmbutil\fR command to configure the \fBex.com\fR environment.
@@ -360,7 +385,6 @@ shown are those set by the previous example.
.sp
.SH FILES
-.sp
.ne 2
.na
\fB\fB$HOME/.nsmbrc\fR\fR
@@ -372,7 +396,6 @@ connection.
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -388,13 +411,11 @@ Interface Stability Committed
.TE
.SH SEE ALSO
-.sp
.LP
\fBsmbutil\fR(1), \fBmount_smbfs\fR(1M), \fBsharectl\fR(1M),
\fBnsswitch.conf\fR(4), \fBuser_attr\fR(4), \fBattributes\fR(5), \fBrbac\fR(5),
\fBsmbfs\fR(7FS)
.SH NOTES
-.sp
.LP
By default, passwords stored in the \fB\&.nsmbrc\fR file are ignored unless
\fBonly\fR the file owner has read and write permission.
diff --git a/usr/src/pkg/manifests/system-library.man3proc.inc b/usr/src/pkg/manifests/system-library.man3proc.inc
index 8528acca7b..0119a81518 100644
--- a/usr/src/pkg/manifests/system-library.man3proc.inc
+++ b/usr/src/pkg/manifests/system-library.man3proc.inc
@@ -11,6 +11,8 @@
#
# Copyright 2018 Joyent, Inc.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
file path=usr/share/man/man3proc/proc_service.3proc
@@ -229,6 +231,7 @@ link path=usr/share/man/man3proc/pr_stat64.3proc target=pr_stat.3proc
link path=usr/share/man/man3proc/Pread_string.3proc target=Pread.3proc
link path=usr/share/man/man3proc/proc_arg_xgrab.3proc target=proc_arg_grab.3proc
link path=usr/share/man/man3proc/proc_arg_xpsinfo.3proc target=proc_arg_psinfo.3proc
+link path=usr/share/man/man3proc/proc_dmodelname.3proc target=proc_fltname.3proc
link path=usr/share/man/man3proc/proc_finistdio.3proc target=proc_initstdio.3proc
link path=usr/share/man/man3proc/proc_flushstdio.3proc target=proc_initstdio.3proc
link path=usr/share/man/man3proc/proc_free_priv.3proc target=proc_get_priv.3proc
diff --git a/usr/src/tools/quick/make-smbclnt b/usr/src/tools/quick/make-smbclnt
index 1b65f50a71..e8c6bfeabc 100755
--- a/usr/src/tools/quick/make-smbclnt
+++ b/usr/src/tools/quick/make-smbclnt
@@ -11,14 +11,11 @@
#
#
-# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
#
-# Use distributed make (dmake) by default.
-make=${MAKE:-dmake}
-
-CLOSED_IS_PRESENT=no
-export CLOSED_IS_PRESENT
+# Use ordinary make (not dmake) by default.
+make=${MAKE:-make}
# Do this if you want to use dbx or gdb
# export SOURCEDEBUG=yes
@@ -97,7 +94,9 @@ fi
# Need some library headers too...
for lib in \
+ libcmdutils \
libcryptoutil \
+ libfakekernel \
libmlrpc \
libpam \
libsec \
@@ -128,7 +127,13 @@ do_kern() {
# skip these on clean (but still nuke them for clobber)
do_lib1() {
- :
+
+for lib in \
+ libavl \
+ libcmdutils
+do
+ (cd $SRC/lib/$lib && $make $1)
+done
}
# lib2 builds stuff we include in the tar file,
@@ -139,7 +144,16 @@ do_lib2() {
(cd $SRC/lib/libsmbfs && $make $1)
[ "$1" = install ] &&
(cd $SRC/lib/libsmbfs && $make _msg)
-(cd $SRC/lib/libmlrpc && $make $1)
+
+for lib in \
+ libfakekernel \
+ libsmbfs \
+ libmlrpc \
+ smbclnt
+do
+ (cd $SRC/lib/$lib && $make $1)
+done
+
(cd $SRC/lib/libshare && $make $1 PLUGINS=smbfs)
(cd $SRC/lib/passwdutil && $make $1)
(cd $SRC/lib/pam_modules/smbfs && $make $1)
@@ -184,6 +198,15 @@ do
(cd $SRC/cmd/mdb/$x/$a/smbfs &&
$make $1 KMDB_LINKTEST_ENABLE= )
done
+
+# mdb_arch is both 32-bit & 64-bit
+for a in $mdb_arch
+do
+ (cd $SRC/cmd/mdb/$x/$a/libfknsmb &&
+ $make $1 )
+ (cd $SRC/cmd/mdb/$x/$a/libfksmbfs &&
+ $make $1 )
+done
}
@@ -199,6 +222,7 @@ do_tags() {
find uts/common/netsmb -name '*.[ch]' -print |sort
find uts/common/fs/smbclnt -name '*.[ch]' -print |sort
find head -name '*.h' -print |sort
+ find lib/smbclnt -name '*.[ch]' -print |sort
find lib/libsmbfs -name '*.[ch]' -print |sort
find cmd/fs.d/smbclnt -name '*.[ch]' -print |sort
find common/smbclnt -name '*.[ch]' -print |sort
@@ -217,9 +241,6 @@ do_tar() {
files="
lib/svc/manifest/network/smb/client.xml
lib/svc/method/smb-client
-opt/smbcl-tests/tests/srvenum
-opt/smbcl-tests/tests/srvinfo
-opt/smbcl-tests/tests/tconn
usr/bin/smbutil
usr/kernel/drv/$arch64/nsmb
usr/kernel/fs/$arch64/smbfs
@@ -239,8 +260,6 @@ usr/lib/libmlrpc.so.2
usr/lib/libsmbfs.so.1
usr/lib/mdb/kvm/$arch64/nsmb.so
usr/lib/mdb/kvm/$arch64/smbfs.so
-usr/lib/mdb/kvm/nsmb.so
-usr/lib/mdb/kvm/smbfs.so
usr/lib/security/$arch64/pam_smbfs_login.so.1
usr/lib/security/pam_smbfs_login.so.1
usr/lib/smbfs/smbiod
diff --git a/usr/src/tools/scripts/wsdiff.py b/usr/src/tools/scripts/wsdiff.py
index 78347ea3b5..aaab371708 100644
--- a/usr/src/tools/scripts/wsdiff.py
+++ b/usr/src/tools/scripts/wsdiff.py
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -46,8 +46,8 @@
# and details about why wsdiff(1) thinks they are different will be logged to
# the results file.
#
-# By invoking nightly(1) with the -w option to NIGHTLY_FLAGS, nightly(1) will use
-# wsdiff(1) to report on what objects changed since the last build.
+# By invoking nightly(1) with the -w option to NIGHTLY_FLAGS, nightly(1) will
+# use wsdiff(1) to report on what objects changed since the last build.
#
# For patch deliverable purposes, it's advised to have nightly do a clobber,
# non-debug build.
@@ -55,8 +55,8 @@
# Think about the results. Was something flagged that you don't expect? Go look
# at the results file to see details about the differences.
#
-# Use the -i option in conjunction with -v and -V to dive deeper and have wsdiff(1)
-# report with more verbosity.
+# Use the -i option in conjunction with -v and -V to dive deeper and have
+# wsdiff(1) report with more verbosity.
#
# Usage: wsdiff [-vVt] [-r results ] [-i filelist ] old new
#
@@ -75,7 +75,11 @@ import datetime, fnmatch, getopt, os, profile, io, subprocess
import re, resource, select, shutil, signal, string, struct, sys, tempfile
import time, threading
from stat import *
-from subprocess import Popen, PIPE
+
+PY3 = sys.version_info[0] == 3
+
+if not PY3:
+ import commands
# Human readable diffs truncated by default if longer than this
# Specifying -v on the command line will override
@@ -116,9 +120,10 @@ wsdiff_exceptions = [
]
def getoutput(cmd):
- p = Popen(cmd, shell=True, stdout=PIPE)
- output, x = p.communicate()
- return (p.returncode, output.decode(errors='replace'))
+ if PY3:
+ return subprocess.getstatusoutput(cmd)
+ else:
+ return commands.getstatusoutput(cmd)
#####
# Logging routines
@@ -224,7 +229,7 @@ def log_difference(f, dtype, diffs) :
#
#
-# Return human readable diffs from two temporary files
+# Return human readable diffs from two files
#
def diffFileData(tmpf1, tmpf2) :
@@ -267,34 +272,6 @@ def diffFileData(tmpf1, tmpf2) :
return data
-#
-# Return human readable diffs betweeen two datasets
-#
-def diffData(base, ptch, d1, d2) :
-
- t = threading.currentThread()
- tmpFile1 = tmpDir1 + os.path.basename(base) + t.getName()
- tmpFile2 = tmpDir2 + os.path.basename(ptch) + t.getName()
-
- try:
- fd1 = io.open(tmpFile1, mode='w', errors='ignore')
- except:
- error("failed to open: " + tmpFile1)
- cleanup(1)
-
- try:
- fd2 = io.open(tmpFile2, mode='w', errors='ignore')
- except:
- error("failed to open: " + tmpFile2)
- cleanup(1)
-
- fd1.write(d1)
- fd2.write(d2)
- fd1.close()
- fd2.close()
-
- return diffFileData(tmpFile1, tmpFile2)
-
#####
# Misc utility functions
#
@@ -456,7 +433,7 @@ def getTheFileType(f) :
elfmagic = b'\177ELF'
def isELF(f) :
try:
- with io.open(f, mode='rb') as fd:
+ with open(f, mode='rb') as fd:
magic = fd.read(len(elfmagic))
if magic == elfmagic :
@@ -471,7 +448,7 @@ def isELF(f) :
#
def isBinary(f) :
try:
- with io.open(f, mode='rb') as fd:
+ with open(f, mode='rb') as fd:
s = fd.read()
if s.find(b'\0') == -1 :
@@ -1056,8 +1033,6 @@ def compareArchives(base, ptch, fileType) :
#####
# (Basic) file comparison
#
-# There's some special case code here for Javadoc HTML files
-#
# Returns 1 if difference detected
# 0 if no difference detected
# -1 on error
@@ -1070,44 +1045,25 @@ def compareBasic(base, ptch, quiet, fileType) :
return 1
try:
- baseFile = io.open(base, errors='replace')
+ with open(base, 'rb') as fh:
+ baseData = fh.read()
except:
error("could not open " + base)
return -1
+
try:
- ptchFile = io.open(ptch, errors='replace')
+ with open(ptch, 'rb') as fh:
+ ptchData = fh.read()
except:
error("could not open " + ptch)
return -1
- baseData = baseFile.read()
- ptchData = ptchFile.read()
-
- baseFile.close()
- ptchFile.close()
-
- needToSnip = False
- if fileType == "HTML" :
- needToSnip = True
- toSnipBeginStr = "<!-- Generated by javadoc"
- toSnipEndStr = "-->\n"
-
- if needToSnip :
- toSnipBegin = baseData.find(toSnipBeginStr)
- if toSnipBegin != -1 :
- toSnipEnd = (baseData[toSnipBegin:].find(toSnipEndStr) +
- len(toSnipEndStr))
- baseData = (baseData[:toSnipBegin] +
- baseData[toSnipBegin + toSnipEnd:])
- ptchData = (ptchData[:toSnipBegin] +
- ptchData[toSnipBegin + toSnipEnd:])
-
if quiet :
if baseData != ptchData :
return 1
else :
if len(baseData) != len(ptchData) or baseData != ptchData :
- diffs = diffData(base, ptch, baseData, ptchData)
+ diffs = diffFileData(base, ptch)
difference(fileName, fileType, diffs)
return 1
return 0
@@ -1147,35 +1103,25 @@ def compareByDumping(base, ptch, quiet, fileType) :
os.system(ptchCmd)
try:
- baseFile = open(tmpFile1)
+ with open(tmpFile1, 'rb') as fh:
+ baseData = fh.read()
except:
error("could not open: " + tmpFile1)
return
+
try:
- ptchFile = open(tmpFile2)
+ with open(tmpFile2, 'rb') as fh:
+ ptchData = fh.read()
except:
error("could not open: " + tmpFile2)
return
- baseData = baseFile.read()
- ptchData = ptchFile.read()
-
- baseFile.close()
- ptchFile.close()
+ ret = 0
if len(baseData) != len(ptchData) or baseData != ptchData :
if not quiet :
data = diffFileData(tmpFile1, tmpFile2);
- try:
- os.unlink(tmpFile1)
- except OSError as e:
- error("compareByDumping: unlink failed %s" % e)
- try:
- os.unlink(tmpFile2)
- except OSError as e:
- error("compareByDumping: unlink failed %s" % e)
- difference(fileName, fileType, data)
- return 1
+ ret = 1
# Remove the temporary files now.
try:
@@ -1187,7 +1133,7 @@ def compareByDumping(base, ptch, quiet, fileType) :
except OSError as e:
error("compareByDumping: unlink failed %s" % e)
- return 0
+ return ret
#####
#
@@ -1487,7 +1433,7 @@ def main() :
if max_threads == -1 :
max_threads = 1
else :
- max_threads += max_threads/5
+ max_threads += int(max_threads/5)
# Set signal handler to attempt graceful exit
debug("Setting signal handler")
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 8b236155fb..1ddfacb0cd 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1301,11 +1301,13 @@ VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o
NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_pass.o \
smb_rq.o smb_sign.o smb_smb.o smb_subrs.o \
smb_time.o smb_tran.o smb_trantcp.o smb_usr.o \
- subr_mchain.o
+ smb2_rq.o smb2_sign.o smb2_smb.o subr_mchain.o \
+ nsmb_sign_kcf.o
SMBFS_COMMON_OBJS += smbfs_ntacl.o
SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \
smbfs_acl.o smbfs_client.o smbfs_smb.o \
+ smbfs_smb1.o smbfs_smb2.o \
smbfs_subr.o smbfs_subr2.o \
smbfs_rwlock.o smbfs_xattr.o \
$(SMBFS_COMMON_OBJS)
diff --git a/usr/src/uts/common/fs/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h
index d25bf0213f..877dc36f9c 100644
--- a/usr/src/uts/common/fs/fs_subr.h
+++ b/usr/src/uts/common/fs/fs_subr.h
@@ -49,7 +49,7 @@ extern "C" {
* Utilities shared among file system implementations.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern int fs_nosys();
extern int fs_inval();
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple
new file mode 100644
index 0000000000..a42fec94d8
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2001 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip
new file mode 100644
index 0000000000..96b9771514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip
@@ -0,0 +1 @@
+PORTIONS OF NSMB DRIVER IN SMB CLIENT
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov
new file mode 100644
index 0000000000..583923c355
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov
@@ -0,0 +1,29 @@
+ Copyright (c) 2000, 2001 Boris Popov
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Boris Popov.
+ 4. Neither the name of the author nor the names of any co-contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip
new file mode 100644
index 0000000000..96b9771514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -0,0 +1 @@
+PORTIONS OF NSMB DRIVER IN SMB CLIENT
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
new file mode 100644
index 0000000000..2be033a8fc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
@@ -0,0 +1,180 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Helper functions for SMB signing using the
+ * Kernel Cryptographic Framework (KCF)
+ *
+ * There are two implementations of these functions:
+ * This one (for kernel) and another for user space:
+ * See: lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+ */
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/crypto/api.h>
+#include <netsmb/smb_signing.h>
+
+/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ crypto_mech_type_t t;
+
+ t = crypto_mech2id(SUN_CKM_MD5);
+ if (t == CRYPTO_MECH_INVALID)
+ return (-1);
+ mech->cm_type = t;
+ return (0);
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
+{
+ int rv;
+
+ rv = crypto_digest_init(mech, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+ crypto_data_t data;
+ int rv;
+
+ bzero(&data, sizeof (data));
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_length = len;
+ data.cd_raw.iov_base = buf;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_digest_update(ctx, &data, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = MD5_DIGEST_LENGTH;
+ out.cd_raw.iov_len = MD5_DIGEST_LENGTH;
+ out.cd_raw.iov_base = (void *)digest16;
+
+ rv = crypto_digest_final(ctx, &out, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * SMB2 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb2_hmac_getmech(smb_sign_mech_t *mech)
+{
+ crypto_mech_type_t t;
+
+ t = crypto_mech2id(SUN_CKM_SHA256_HMAC);
+ if (t == CRYPTO_MECH_INVALID)
+ return (-1);
+ mech->cm_type = t;
+ return (0);
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ crypto_key_t ckey;
+ int rv;
+
+ bzero(&ckey, sizeof (ckey));
+ ckey.ck_format = CRYPTO_KEY_RAW;
+ ckey.ck_data = key;
+ ckey.ck_length = key_len * 8; /* in bits */
+
+ rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ crypto_data_t data;
+ int rv;
+
+ bzero(&data, sizeof (data));
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_length = len;
+ data.cd_raw.iov_base = (void *)in;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_mac_update(ctx, &data, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Note, the SMB2 signature is the first 16 bytes of the
+ * 32-byte SHA256 HMAC digest.
+ */
+int
+smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ uint8_t full_digest[SHA256_DIGEST_LENGTH];
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = SHA256_DIGEST_LENGTH;
+ out.cd_raw.iov_len = SHA256_DIGEST_LENGTH;
+ out.cd_raw.iov_base = (void *)full_digest;
+
+ rv = crypto_mac_final(ctx, &out, 0);
+ if (rv == CRYPTO_SUCCESS)
+ bcopy(full_digest, digest16, 16);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
index 993bdd61a8..a78b08bba0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
@@ -20,7 +20,7 @@
\
\
-\ Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+\ Copyright 2018 Nexenta Systems, Inc. All rights reserved.
\ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
@@ -52,8 +52,10 @@ smbioc_ssn_ident
id_user
smbioc_ossn
- ssn_vopt
ssn_owner
+ ssn_vopt
+ ssn_minver
+ ssn_maxver
ssn_id
ssn_srvname
@@ -68,77 +70,30 @@ smbioc_tcon
tc_opt
tc_sh
-smb_sopt
- sv_proto
- sv_sm
- sv_tz
- sv_maxmux
- sv_maxvcs
- sv_rawmode
- sv_maxtx
- sv_maxraw
- sv_skey
- sv_caps
-
-smb_iods
- is_tran_fd
- is_vcflags
- is_hflags
- is_hflags2
- is_smbuid
- is_next_mid
- is_txmax
- is_rwmax
- is_rxmax
- is_wxmax
- is_ssn_key
- is_next_seq
- is_u_maclen
- is_u_mackey
-
smbioc_ssn_work
- wk_iods
- wk_sopt
wk_out_state
-
-smbioc_rq SIZEOF_SMBIOC_RQ
- ioc_cmd
- ioc_errclass IOC_RQ_ERRCLASS
- ioc_serror IOC_RQ_SERROR
- ioc_error IOC_RQ_ERROR
- ioc_tbufsz
- ioc_rbufsz
- _ioc_tbuf
- _ioc_rbuf
-
-smbioc_t2rq SIZEOF_SMBIOC_T2RQ
- ioc_setup
- ioc_setupcnt
- ioc_name IOC_T2_NAME
- ioc_tparamcnt
- ioc_tdatacnt
- ioc_rparamcnt
- ioc_rdatacnt
- ioc_errclass IOC_T2_ERRCLASS
- ioc_serror IOC_T2_SERROR
- ioc_error IOC_T2_ERROR
- ioc_rpflags2
- _ioc_tparam
- _ioc_tdata
- _ioc_rparam
- _ioc_rdata
-
-smbioc_flags SIZEOF_SMBIOC_FLAGS
- ioc_level
- ioc_mask
- ioc_flags
+ wk_u_ssnkey_len
+ wk_u_ssnkey_buf
+ wk_u_auth_rlen
+ wk_u_auth_wlen
+ wk_u_auth_rbuf
+ wk_u_auth_wbuf
+ wk_cl_guid
smbioc_rw SIZEOF_SMBIOC_RW
- ioc_fh
ioc_cnt
+ ioc_flags
_ioc_offset
_ioc_base
+smbioc_xnp SIZEOF_SMBIOC_XNP
+ ioc_tdlen
+ ioc_rdlen
+ ioc_more
+ ioc_pad1
+ _ioc_tdata
+ _ioc_rdata
+
smbioc_ntcreate SIZEOF_NTCREATE
ioc_req_acc
ioc_efattr
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c
new file mode 100644
index 0000000000..44041ad975
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/atomic.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+static const uint8_t SMB2_SIGNATURE[4] = SMB2_PROTOCOL_ID;
+
+static int smb2_rq_enqueue(struct smb_rq *rqp);
+static int smb2_rq_reply(struct smb_rq *rqp);
+
+/*
+ * Given a request with it's body already composed,
+ * rewind to the start and fill in the SMB2 header.
+ * This is called when the request is enqueued,
+ * so we have the final message ID etc.
+ */
+void
+smb2_rq_fillhdr(struct smb_rq *rqp)
+{
+ struct mbchain mbtmp, *mbp = &mbtmp;
+ uint16_t creditcharge, creditrequest;
+ size_t len;
+ mblk_t *m;
+
+ ASSERT((rqp->sr2_nextcmd & 7) == 0);
+ if (rqp->sr2_nextcmd != 0) {
+ len = msgdsize(rqp->sr_rq.mb_top);
+ ASSERT((len & 7) == 0);
+ }
+
+ /*
+ * When sending negotiate, we don't technically know yet
+ * if the server handles SMB 2.1 or later and credits.
+ * Negotiate is supposed to set these to zero.
+ */
+ if (rqp->sr2_command == SMB2_NEGOTIATE) {
+ creditcharge = creditrequest = 0;
+ } else {
+ creditcharge = rqp->sr2_creditcharge;
+ creditrequest = rqp->sr2_creditsrequested;
+ }
+
+ /*
+ * Fill in the SMB2 header using a dup of the first mblk,
+ * which points at the same data but has its own wptr,
+ * so we can rewind without trashing the message.
+ */
+ m = dupb(rqp->sr_rq.mb_top);
+ m->b_wptr = m->b_rptr; /* rewind */
+ mb_initm(mbp, m);
+
+ mb_put_mem(mbp, SMB2_SIGNATURE, 4, MB_MSYSTEM);
+ mb_put_uint16le(mbp, SMB2_HDR_SIZE); /* Struct Size */
+ mb_put_uint16le(mbp, creditcharge);
+ mb_put_uint32le(mbp, 0); /* Status */
+ mb_put_uint16le(mbp, rqp->sr2_command);
+ mb_put_uint16le(mbp, creditrequest);
+ mb_put_uint32le(mbp, rqp->sr2_rqflags);
+ mb_put_uint32le(mbp, rqp->sr2_nextcmd);
+ mb_put_uint64le(mbp, rqp->sr2_messageid);
+
+ mb_put_uint32le(mbp, rqp->sr_pid); /* Process ID */
+ mb_put_uint32le(mbp, rqp->sr2_rqtreeid); /* Tree ID */
+ mb_put_uint64le(mbp, rqp->sr2_rqsessionid); /* Session ID */
+ /* The MAC signature is filled in by smb2_vc_sign() */
+
+ /* This will free the mblk from dupb. */
+ mb_done(mbp);
+}
+
+int
+smb2_rq_simple(struct smb_rq *rqp)
+{
+ return (smb2_rq_simple_timed(rqp, smb2_timo_default));
+}
+
+/*
+ * Simple request-reply exchange
+ */
+int
+smb2_rq_simple_timed(struct smb_rq *rqp, int timeout)
+{
+ int error;
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ error = smb2_rq_enqueue(rqp);
+ if (error == 0)
+ error = smb2_rq_reply(rqp);
+
+ return (error);
+}
+
+
+static int
+smb2_rq_enqueue(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_share *ssp = rqp->sr_share;
+ int error = 0;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ /*
+ * Normal requests may initiate a reconnect,
+ * and/or wait for state changes to finish.
+ * Some requests set the NORECONNECT flag
+ * to avoid all that (i.e. tree discon)
+ */
+ if (rqp->sr_flags & SMBR_NORECONNECT) {
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
+ }
+ if (ssp != NULL &&
+ ((ssp->ss_flags & SMBS_CONNECTED) == 0))
+ return (ENOTCONN);
+ goto ok_out;
+ }
+
+ /*
+ * If we're not connected, initiate a reconnect
+ * and/or wait for an existing one to finish.
+ */
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ error = smb_iod_reconnect(vcp);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * If this request has a "share" object
+ * that needs a tree connect, do it now.
+ */
+ if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
+ error = smb_share_tcon(ssp, rqp->sr_cred);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * We now know what UID + TID to use.
+ * Store them in the request.
+ */
+ok_out:
+ rqp->sr2_rqsessionid = vcp->vc2_session_id;
+ rqp->sr2_rqtreeid = ssp ? ssp->ss2_tree_id : SMB2_TID_UNKNOWN;
+ error = smb2_iod_addrq(rqp);
+
+ return (error);
+}
+
+/*
+ * Used by the IOD thread during connection setup,
+ * and for smb2_echo after network timeouts. Note that
+ * unlike smb2_rq_simple, callers must check sr_error.
+ */
+int
+smb2_rq_internal(struct smb_rq *rqp, int timeout)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int error;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ /*
+ * In-line smb2_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. for an internal request.
+ */
+ rqp->sr2_rqsessionid = vcp->vc2_session_id;
+ rqp->sr2_rqtreeid = SMB2_TID_UNKNOWN;
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb2_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * In-line a variant of smb2_rq_reply(rqp) here as we may
+ * need to do custom parsing for SMB1-to-SMB2 negotiate.
+ */
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq_int(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ error = smb2_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB2 header.
+ */
+ error = smb2_rq_parsehdr(rqp);
+
+ /*
+ * Skip the error translation smb2_rq_reply does.
+ * Callers of this expect "raw" NT status.
+ */
+
+ return (error);
+}
+
+/*
+ * Wait for a reply to this request, then parse it.
+ */
+static int
+smb2_rq_reply(struct smb_rq *rqp)
+{
+ int error;
+
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ error = smb2_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB2 header
+ */
+ error = smb2_rq_parsehdr(rqp);
+ if (error != 0)
+ return (error);
+
+ if (rqp->sr_error != 0) {
+ error = smb_maperr32(rqp->sr_error);
+ }
+
+ if (error != 0) {
+ /*
+ * Do a special check for STATUS_BUFFER_OVERFLOW;
+ * it's not an error.
+ */
+ if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) {
+ /*
+ * Don't report it as an error to our caller;
+ * they can look at rqp->sr_error if they
+ * need to know whether we got a
+ * STATUS_BUFFER_OVERFLOW.
+ */
+ rqp->sr_flags |= SMBR_MOREDATA;
+ error = 0;
+ }
+ } else {
+ rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
+
+ return (error);
+}
+
+/*
+ * Parse the SMB 2+ Header
+ */
+int
+smb2_rq_parsehdr(struct smb_rq *rqp)
+{
+ struct mdchain *mdp = &rqp->sr_rp;
+ uint32_t protocol_id;
+ uint16_t length = 0;
+ uint16_t credit_charge;
+ uint16_t command;
+ uint64_t message_id = 0;
+ int error = 0;
+
+ /* Get Protocol ID */
+ md_get_uint32le(mdp, &protocol_id);
+
+ /* Get/Check structure size is 64 */
+ md_get_uint16le(mdp, &length);
+ if (length != 64)
+ return (EBADRPC);
+
+ md_get_uint16le(mdp, &credit_charge);
+ md_get_uint32le(mdp, &rqp->sr_error);
+ md_get_uint16le(mdp, &command);
+ md_get_uint16le(mdp, &rqp->sr2_rspcreditsgranted);
+ md_get_uint32le(mdp, &rqp->sr2_rspflags);
+ md_get_uint32le(mdp, &rqp->sr2_rspnextcmd);
+ md_get_uint64le(mdp, &message_id);
+
+ if ((rqp->sr2_rspflags & SMB2_FLAGS_ASYNC_COMMAND) == 0) {
+ /*
+ * Sync Header
+ */
+
+ /* Get Process ID */
+ md_get_uint32le(mdp, &rqp->sr2_rsppid);
+
+ /* Get Tree ID */
+ md_get_uint32le(mdp, &rqp->sr2_rsptreeid);
+ } else {
+ /*
+ * Async Header
+ */
+
+ /* Get Async ID */
+ md_get_uint64le(mdp, &rqp->sr2_rspasyncid);
+ }
+
+ /* Get Session ID */
+ error = md_get_uint64le(mdp, &rqp->sr2_rspsessionid);
+ if (error)
+ return (error);
+
+ /* Skip MAC Signature */
+ error = md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h
new file mode 100644
index 0000000000..812c679b2f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _NETSMB_SMB2_RQ_H_
+#define _NETSMB_SMB2_RQ_H_
+
+#include <sys/types.h>
+
+/*
+ * Note: Pad all structures to 8 byte boundaries
+ */
+
+int smb2_rq_parsehdr(struct smb_rq *rqp);
+void smb2_rq_fillhdr(struct smb_rq *rqp);
+
+int smb2_rq_simple(struct smb_rq *rqp);
+int smb2_rq_simple_timed(struct smb_rq *rqp, int timeout);
+int smb2_rq_internal(struct smb_rq *rqp, int timeout);
+
+#endif /* _NETSMB_SMB2_RQ_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
new file mode 100644
index 0000000000..46bf28c370
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
@@ -0,0 +1,253 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Support for SMB2 "signing" (message integrity)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+#include <sys/des.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
+
+#define SMB2_SIG_OFF 48
+#define SMB2_SIG_LEN 16
+
+/*
+ * smb2_sign_init
+ *
+ * Get the mechanism info and initilize SMB2 signing.
+ */
+int
+smb2_sign_init(smb_vc_t *vcp)
+{
+ uint_t copysize;
+ int rc;
+
+ ASSERT(vcp->vc_ssnkey != NULL);
+ ASSERT(vcp->vc_mackey == NULL);
+
+ rc = smb2_hmac_getmech(&vcp->vc_signmech);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb2 can't get signing mechanism");
+ return (EAUTH);
+ }
+
+ /*
+ * Convert the session key to the MAC key.
+ *
+ * For SMB2, the signing key is just the first 16 bytes
+ * of the session key (truncated or padded with zeros).
+ * [MS-SMB2] 3.2.5.3.1
+ *
+ * SMB3 would do KDF here.
+ */
+ vcp->vc_mackeylen = SMB2_SIG_LEN;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ copysize = vcp->vc_ssnkeylen;
+ if (copysize > vcp->vc_mackeylen)
+ copysize = vcp->vc_mackeylen;
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
+
+ return (0);
+}
+
+
+/*
+ * Compute MAC signature of packet data, using the stored MAC key.
+ *
+ * The signature is in the last 16 bytes of the SMB2 header.
+ * The signature algorighm is to compute HMAC SHA256 over the
+ * entire command, with the signature field set to zeros.
+ *
+ * See similar code for the server side:
+ * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc
+ */
+static int
+smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
+{
+ uint8_t tmp_hdr[SMB2_HDR_SIZE];
+ smb_sign_ctx_t ctx = 0;
+ mblk_t *m = mp;
+ int size;
+ int rc;
+
+ if (vcp->vc_mackey == NULL)
+ return (-1);
+
+ rc = smb2_hmac_init(&ctx, &vcp->vc_signmech,
+ vcp->vc_mackey, vcp->vc_mackeylen);
+ if (rc != 0)
+ return (rc);
+
+ /* Our caller should ensure mp has a contiguous header */
+ ASSERT(m != NULL);
+ ASSERT(MBLKL(m) >= SMB2_HDRLEN);
+
+ /*
+ * Copy of the SMB2 header, zero out the signature, and digest.
+ */
+ size = SMB2_HDRLEN;
+ bcopy(m->b_rptr, tmp_hdr, size);
+ bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN);
+ rc = smb2_hmac_update(ctx, tmp_hdr, size);
+ if (rc != 0)
+ return (rc);
+
+ /*
+ * Digest the rest of the SMB2 header packet, starting at
+ * the data just after the SMB2 header.
+ */
+ size = MBLKL(m) - SMB2_HDRLEN;
+ rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
+ if (rc != 0)
+ return (rc);
+ m = m->b_cont;
+
+ /* Digest rest of the SMB2 message. */
+ while (m != NULL) {
+ size = MBLKL(m);
+ if (size > 0) {
+ rc = smb2_hmac_update(ctx, m->b_rptr, size);
+ if (rc != 0)
+ return (rc);
+ }
+ m = m->b_cont;
+ }
+ rc = smb2_hmac_final(ctx, signature);
+
+ return (rc);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+void
+smb2_rq_sign(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rq.mb_top;
+ uint8_t *sigloc;
+ int rc;
+
+ /*
+ * smb_rq_new() ensures this,
+ * but just in case..
+ */
+ ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
+ sigloc = mp->b_rptr + SMB2_SIG_OFF;
+
+ if (vcp->vc_mackey == NULL)
+ return;
+
+ /*
+ * This will compute the MAC and store it
+ * directly into the message at sigloc.
+ */
+ rc = smb2_compute_MAC(vcp, mp, sigloc);
+ if (rc != 0) {
+ SMBSDEBUG("Crypto error %d", rc);
+ bzero(sigloc, SMB2_SIG_LEN);
+ }
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb2_rq_verify(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rp.md_top;
+ uint8_t sigbuf[SMB2_SIG_LEN];
+ uint8_t *sigloc;
+ int rc;
+
+ /*
+ * Note vc_mackey and vc_mackeylen gets filled in by
+ * smb_usr_iod_work as the connection comes in.
+ */
+ if (vcp->vc_mackey == NULL) {
+ SMBSDEBUG("no mac key\n");
+ return (0);
+ }
+
+ /*
+ * Let caller deal with empty reply or short messages by
+ * returning zero. Caller will fail later, in parsing.
+ */
+ if (mp == NULL) {
+ SMBSDEBUG("empty reply\n");
+ return (0);
+ }
+
+ /* smb2_iod_process ensures this */
+ ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
+ sigloc = mp->b_rptr + SMB2_SIG_OFF;
+
+ /*
+ * Compute the expected signature in sigbuf.
+ */
+ rc = smb2_compute_MAC(vcp, mp, sigbuf);
+ if (rc != 0) {
+ SMBSDEBUG("Crypto error %d", rc);
+ /*
+ * If we can't compute a MAC, then there's
+ * no point trying other seqno values.
+ */
+ return (EBADRPC);
+ }
+
+ /*
+ * Compare the computed signature with the
+ * one found in the message (at sigloc)
+ */
+ if (bcmp(sigbuf, sigloc, SMB2_SIG_LEN) == 0)
+ return (0);
+
+ SMBERROR("BAD signature, Server=%s MID=0x%llx\n",
+ vcp->vc_srvname, (long long)rqp->sr2_messageid);
+
+ return (EBADRPC);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
new file mode 100644
index 0000000000..c3df18faa9
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/random.h>
+#include <sys/note.h>
+#include <sys/errno.h>
+#include <sys/cmn_err.h>
+
+#include <smb/ntaccess.h>
+#include <smb/winioctl.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+#define NDIALECTS 1
+static const uint16_t smb2_dialects[1] = {
+ SMB2_DIALECT_0210
+};
+
+/* Optional capabilities we advertise (none yet). */
+uint32_t smb2_clnt_caps = 0;
+
+/* How many credits to ask for during ssn. setup. */
+uint16_t smb2_ss_req_credits = 64;
+
+/*
+ * Default timeout values, all in seconds.
+ * Make these tunable (only via mdb for now).
+ */
+int smb2_timo_notice = 15;
+int smb2_timo_default = 30;
+int smb2_timo_logon = 45;
+int smb2_timo_open = 45;
+int smb2_timo_read = 45;
+int smb2_timo_write = 60;
+int smb2_timo_append = 90;
+
+/*
+ * This is a special handler for the odd SMB1-to-SMB2 negotiate
+ * response, where an SMB1 request gets an SMB2 response.
+ *
+ * Unlike most parse functions here, this needs to parse both
+ * the SMB2 header and the nego. response body. Note that
+ * the only "SMB2" dialect our SMB1 negotiate offered was
+ * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
+ * SMB2 dialect we should get is: SMB2_DIALECT_02ff
+ */
+int
+smb2_parse_smb1nego_resp(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_sopt *sp = &vcp->vc_sopt;
+ struct mdchain *mdp;
+ uint16_t length = 0;
+ int error;
+
+ /* Get pointer to response data */
+ smb_rq_getreply(rqp, &mdp);
+
+ error = smb2_rq_parsehdr(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Parse SMB 2/3 Negotiate Response
+ * We are already pointing to begining of Response data
+ */
+
+ /* Check structure size is 65 */
+ md_get_uint16le(mdp, &length);
+ if (length != 65)
+ return (EBADRPC);
+
+ /* Get Security Mode */
+ md_get_uint16le(mdp, &sp->sv2_security_mode);
+
+ /* Get Dialect. */
+ error = md_get_uint16le(mdp, &sp->sv2_dialect);
+ if (error != 0)
+ return (error);
+
+ /* What dialect did we get? */
+ if (sp->sv2_dialect != SMB2_DIALECT_02ff) {
+ SMBERROR("Unknown dialect 0x%x\n", sp->sv2_dialect);
+ return (EINVAL);
+ }
+ /* Set our (internal) SMB1 dialect also. */
+ sp->sv_proto = SMB_DIALECT_SMB2_FF;
+
+ /*
+ * This request did not go through smb2_iod_addrq and
+ * smb2_iod_process() so the SMB2 message ID state is
+ * behind what we need it to be. Fix that.
+ */
+ vcp->vc2_next_message_id = 1;
+ vcp->vc2_limit_message_id = 2;
+
+ /*
+ * Skip parsing the rest. We'll get a normal
+ * SMB2 negotiate next and do negotiate then.
+ */
+ return (0);
+}
+
+int
+smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sp = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ uint16_t ndialects = NDIALECTS;
+ boolean_t will_sign = B_FALSE;
+ uint16_t length = 0;
+ uint16_t security_mode;
+ uint16_t sec_buf_off;
+ uint16_t sec_buf_len;
+ int err, i;
+
+ /*
+ * Compute security mode
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ } else {
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ }
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB2 negotiate request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 36); /* Struct Size */
+ mb_put_uint16le(mbp, ndialects); /* Dialect Count */
+ mb_put_uint16le(mbp, security_mode);
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, smb2_clnt_caps);
+ mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
+ mb_put_uint64le(mbp, 0); /* Start Time */
+ for (i = 0; i < ndialects; i++) { /* Dialects */
+ mb_put_uint16le(mbp, smb2_dialects[i]);
+ }
+
+ /*
+ * Do the OTW call.
+ */
+ err = smb2_rq_internal(rqp, smb2_timo_default);
+ if (err) {
+ goto errout;
+ }
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Decode the negotiate response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ md_get_uint16le(mdp, &length); /* Struct size */
+ if (length != 65) {
+ err = EBADRPC;
+ goto errout;
+ }
+
+ md_get_uint16le(mdp, &sp->sv2_security_mode);
+ md_get_uint16le(mdp, &sp->sv2_dialect);
+ md_get_uint16le(mdp, NULL); /* reserved */
+ md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
+ md_get_uint32le(mdp, &sp->sv2_capabilities);
+ md_get_uint32le(mdp, &sp->sv2_maxtransact);
+ md_get_uint32le(mdp, &sp->sv2_maxread);
+ md_get_uint32le(mdp, &sp->sv2_maxwrite);
+ md_get_uint64le(mdp, NULL); /* curr_time */
+ md_get_uint64le(mdp, NULL); /* boot_time */
+
+ /* Get Security Blob offset and length */
+ md_get_uint16le(mdp, &sec_buf_off);
+ err = md_get_uint16le(mdp, &sec_buf_len);
+ if (err != 0)
+ goto errout;
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /*
+ * Security buffer offset is from the beginning of SMB 2 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 64
+ */
+ if (sec_buf_len != 0) {
+ int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
+ if (skip < 0) {
+ err = EBADRPC;
+ goto errout;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sec_buf_len) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
+ sec_buf_len, MB_MUSER);
+ if (err) {
+ goto errout;
+ }
+ }
+
+ /*
+ * Decoded everything. Now decisions.
+ */
+
+ /*
+ * Turn on signing if either Server or client requires it,
+ * except: anonymous sessions can't sign.
+ */
+ if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
+ (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
+ will_sign = B_TRUE;
+ if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
+ will_sign = B_FALSE;
+ SMBSDEBUG("Security signatures: %d", (int)will_sign);
+ if (will_sign)
+ vcp->vc_flags |= SMBV_SIGNING;
+
+ /*
+ * ToDo - too many places are looking at sv_caps, so for now
+ * set the SMB1 capabilities too. Later we should use the
+ * sv2_capabilities for SMB 2+.
+ */
+ sp->sv_caps = (SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_LARGE_READX |
+ SMB_CAP_LARGE_WRITEX |
+ SMB_CAP_EXT_SECURITY);
+ if (sp->sv2_capabilities & SMB2_CAP_DFS)
+ sp->sv_caps |= SMB_CAP_DFS;
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sp->sv2_maxread < 0x8000) {
+ SMBSDEBUG("maxread too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+ if (sp->sv2_maxwrite < 0x8000) {
+ SMBSDEBUG("maxwrite too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+ if (sp->sv2_maxtransact < 0x4000) {
+ SMBSDEBUG("maxtransact too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /* Here too, fill SMB1 fields */
+ vcp->vc_rxmax = sp->sv2_maxread;
+ vcp->vc_wxmax = sp->sv2_maxwrite;
+ vcp->vc_txmax = sp->sv2_maxtransact;
+
+ smb_rq_done(rqp);
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
+
+int
+smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ // smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ char *sb;
+ int err, ret;
+ uint16_t sblen;
+ uint16_t length = 0;
+ uint16_t session_flags;
+ uint16_t sec_buf_off;
+ uint16_t sec_buf_len;
+ uint8_t security_mode;
+
+ /*
+ * Compute security mode
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ } else {
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ }
+
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Always ask for some credits. The server usually will
+ * only grant these credits once we've authenticated.
+ */
+ rqp->sr2_creditsrequested = smb2_ss_req_credits;
+
+ /*
+ * Build the SMB Session Setup request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+
+ mb_put_uint16le(mbp, 25); /* Struct size */
+ mb_put_uint8(mbp, 0); /* VcNumber */
+ mb_put_uint8(mbp, security_mode);
+ mb_put_uint32le(mbp, smb2_clnt_caps); /* Capabilities */
+ mb_put_uint32le(mbp, 0); /* Channel - always 0 */
+
+ /*
+ * Security buffer offset and length. Normally would use
+ * ptr = mb_reserve() and fill in later, but since only a
+ * small amount of fixed-size stuff follows (12 bytes)
+ * we can just compute the offset now.
+ */
+ mb_put_uint16le(mbp, mbp->mb_count + 12);
+ mb_put_uint16le(mbp, sblen);
+ mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Run the request. The return value here should be the
+ * return from this function, unless we fail decoding.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
+ */
+ ret = smb2_rq_internal(rqp, smb2_timo_logon);
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
+ goto out;
+ }
+
+ /*
+ * After the first Session Setup Response,
+ * save the session ID.
+ */
+ if (vcp->vc2_session_id == 0)
+ vcp->vc2_session_id = rqp->sr2_rspsessionid;
+
+ /*
+ * Decode the session setup response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ md_get_uint16le(mdp, &length); /* Struct size */
+ if (length != 9) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint16le(mdp, &session_flags);
+ md_get_uint16le(mdp, &sec_buf_off);
+ err = md_get_uint16le(mdp, &sec_buf_len);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Security buffer offset is from the beginning of SMB 2 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 8
+ */
+ if (sec_buf_len != 0) {
+ int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sec_buf_len) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sec_buf_len;
+ ret = EMSGSIZE;
+ goto out;
+ }
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
+ sec_buf_len, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ }
+
+out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* Session ID no longer valid. */
+ vcp->vc2_session_id = 0;
+ }
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+}
+
+int
+smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc2_session_id == 0)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Fill in Logoff part
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+ struct smb_vc *vcp;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ char *unc_name = NULL;
+ int error, unc_len;
+ uint16_t plen, *plenp;
+ uint16_t options = 0;
+ uint_t cnt0;
+ uint32_t net_stype;
+ uint16_t structure_size = 0;
+ uint8_t smb2stype;
+
+ vcp = SSTOVC(ssp);
+
+ /*
+ * Make this a "VC-level" request, so it will have
+ * rqp->sr_share == NULL, and smb_iod_sendrq()
+ * will send it with TID = SMB_TID_UNKNOWN
+ *
+ * This also serves to bypass the wait for
+ * share state changes, which this call is
+ * trying to carry out.
+ */
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the UNC name, i.e. "//server/share"
+ * but with backslashes of course.
+ * size math: three slashes, one null.
+ */
+ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
+ unc_name = kmem_alloc(unc_len, KM_SLEEP);
+ (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
+ vcp->vc_srvname, ssp->ss_name);
+ SMBSDEBUG("unc_name: \"%s\"", unc_name);
+
+ /*
+ * Build the request.
+ */
+ mbp = &rqp->sr_rq;
+
+ mb_put_uint16le(mbp, 9); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint16le(mbp, 72); /* Path Offset */
+
+ /*
+ * Fill in path length after we put the string, so we know
+ * the length after conversion from UTF-8 to UCS-2.
+ */
+ plenp = mb_reserve(mbp, 2);
+ cnt0 = mbp->mb_count;
+
+ /* UNC resource name (without the null) */
+ error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
+ SMB_CS_NONE, NULL);
+ if (error)
+ goto out;
+
+ /* Now go back and fill in the path length. */
+ plen = (uint16_t)(mbp->mb_count - cnt0);
+ *plenp = htoles(plen);
+
+ /*
+ * Run the request.
+ *
+ * Using NOINTR_RECV because we don't want to risk
+ * missing a successful tree connect response,
+ * which would "leak" Tree IDs.
+ */
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+ error = smb2_rq_simple(rqp);
+ SMBSDEBUG("%d\n", error);
+ if (error) {
+ /*
+ * If we get the server name wrong, i.e. due to
+ * mis-configured name services, this will be
+ * NT_STATUS_DUPLICATE_NAME. Log this error.
+ */
+ SMBERROR("(%s) failed, status=0x%x",
+ unc_name, rqp->sr_error);
+ goto out;
+ }
+
+ /*
+ * Parse the tree connect response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 16 */
+ md_get_uint16le(mdp, &structure_size);
+ if (structure_size != 16) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint8(mdp, &smb2stype);
+ md_get_uint8(mdp, NULL); /* reserved */
+ md_get_uint32le(mdp, &ssp->ss2_share_flags);
+ md_get_uint32le(mdp, &ssp->ss2_share_caps);
+ error = md_get_uint32le(mdp, NULL); /* maxAccessRights */
+ if (error)
+ goto out;
+
+ /*
+ * Convert SMB2 share type to NetShareEnum share type
+ */
+ switch (smb2stype) {
+ case SMB2_SHARE_TYPE_DISK:
+ net_stype = STYPE_DISKTREE;
+ break;
+ case SMB2_SHARE_TYPE_PIPE:
+ net_stype = STYPE_IPC;
+ break;
+ case SMB2_SHARE_TYPE_PRINT:
+ net_stype = STYPE_PRINTQ;
+ break;
+ default:
+ net_stype = STYPE_UNKNOWN;
+ break;
+ }
+ ssp->ss_type = net_stype;
+
+ /*
+ * Map SMB 2/3 capabilities to SMB 1 options,
+ * for common code that looks there.
+ */
+ if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
+ options |= SMB_SHARE_IS_IN_DFS;
+
+ /* Update share state */
+ SMB_SS_LOCK(ssp);
+ ssp->ss2_tree_id = rqp->sr2_rsptreeid;
+ ssp->ss_vcgenid = vcp->vc_genid;
+ ssp->ss_options = options;
+ ssp->ss_flags |= SMBS_CONNECTED;
+ SMB_SS_UNLOCK(ssp);
+
+out:
+ if (unc_name)
+ kmem_free(unc_name, unc_len);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+ struct smb_vc *vcp;
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
+ return (0);
+
+ /*
+ * Build this as a "VC-level" request, so it will
+ * avoid testing the _GONE flag on the share,
+ * which has already been set at this point.
+ * Add the share pointer "by hand" below, so
+ * smb_iod_sendrq will plug in the TID.
+ */
+ vcp = SSTOVC(ssp);
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
+ if (error)
+ return (error);
+ rqp->sr_share = ssp; /* See "by hand" above. */
+
+ /*
+ * Fill in SMB2 Tree Disconnect part
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here, but we
+ * do need to make sure we send this out, or we could
+ * "leak" active tree IDs on interrupt or timeout.
+ * The NOINTR_SEND flag makes this request immune to
+ * interrupt or timeout until the send is done.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
+ error = smb2_rq_simple_timed(rqp, 5);
+
+ smb_rq_done(rqp);
+
+ /* Whether we get an error or not... */
+ ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
+
+ return (error);
+}
+
+/*
+ * Put the name, first skipping a leading slash.
+ */
+static int
+put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
+{
+ mblk_t *m;
+
+ if (name_mbp == NULL)
+ return (0);
+ m = name_mbp->mb_top;
+ if (m == NULL)
+ return (0);
+
+ /* Use a dup of the message to leave the passed one untouched. */
+ m = dupmsg(m);
+ if (m == NULL)
+ return (ENOSR);
+
+ if (MBLKL(m) >= 2 &&
+ m->b_rptr[0] == '\\' &&
+ m->b_rptr[1] == '\0')
+ m->b_rptr += 2;
+
+ return (mb_put_mbuf(mbp, m));
+}
+
+/*
+ * Modern create/open of file or directory.
+ *
+ * The passed name is a full path relative to the share root.
+ * Callers prepare paths with a leading slash (backslash)
+ * because that's what SMB1 expected. SMB2 does not allow the
+ * leading slash here. To make life simpler for callers skip a
+ * leading slash here. That allows callers use use common logic
+ * for building paths without needing to know if the connection
+ * is using SMB1 or SMB2 (just build paths with a leading slash).
+ */
+int
+smb2_smb_ntcreate(
+ struct smb_share *ssp,
+ struct mbchain *name_mb,
+ struct mbchain *cctx_in,
+ struct mdchain *cctx_out,
+ uint32_t cr_flags, /* create flags */
+ uint32_t req_acc, /* requested access */
+ uint32_t efa, /* ext. file attrs (DOS attr +) */
+ uint32_t share_acc,
+ uint32_t open_disp, /* open disposition */
+ uint32_t createopt, /* NTCREATEX_OPTIONS_ */
+ uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */
+ struct smb_cred *scrp,
+ smb2fid_t *fidp, /* returned FID */
+ uint32_t *cr_act_p, /* optional create action */
+ struct smbfattr *fap) /* optional attributes */
+{
+ struct smbfattr fa;
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t *name_offp;
+ uint16_t *name_lenp;
+ uint32_t *cctx_offp;
+ uint32_t *cctx_lenp;
+ uint32_t rcc_off, rcc_len;
+ smb2fid_t smb2_fid;
+ uint64_t llongint;
+ uint32_t longint, createact;
+ uint_t off, len;
+ int error;
+ uint16_t StructSize = 57; // [MS-SMB2]
+
+ bzero(&fa, sizeof (fa));
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Todo: Assemble creat contexts (if needed)
+ * into an mbchain.
+ */
+
+ /*
+ * Build the SMB 2/3 Create Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, StructSize);
+ mb_put_uint8(mbp, 0); /* Security flags */
+ mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */
+ mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
+ mb_put_uint64le(mbp, cr_flags);
+ mb_put_uint64le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, req_acc);
+ mb_put_uint32le(mbp, efa); /* File attributes */
+ mb_put_uint32le(mbp, share_acc); /* Share access */
+ mb_put_uint32le(mbp, open_disp); /* Create disposition */
+ mb_put_uint32le(mbp, createopt); /* Create options */
+
+ name_offp = mb_reserve(mbp, 2); /* Name offset */
+ name_lenp = mb_reserve(mbp, 2); /* Name len */
+
+ cctx_offp = mb_reserve(mbp, 4); /* Context offset */
+ cctx_lenp = mb_reserve(mbp, 4); /* Context len */
+
+ /*
+ * Put the file name, which is provided in an mbchain.
+ * If there's a leading slash, skip it (see above).
+ */
+ off = mbp->mb_count;
+ *name_offp = htoles((uint16_t)off);
+ error = put_name_skip_slash(mbp, name_mb);
+ if (error)
+ goto out;
+ len = mbp->mb_count - off;
+ *name_lenp = htoles((uint16_t)len);
+
+ /*
+ * Now the create contexts (if provided)
+ */
+ if (cctx_in != NULL) {
+ off = mbp->mb_count;
+ *cctx_offp = htolel((uint32_t)off);
+ mb_put_mbchain(mbp, cctx_in);
+ len = mbp->mb_count - off;
+ *cctx_lenp = htolel((uint32_t)len);
+ } else {
+ *cctx_offp = 0;
+ *cctx_lenp = 0;
+ }
+
+ /*
+ * If we didn't put any variable-sized data, we'll have
+ * put exactly 56 bytes of data, and we need to pad out
+ * this request to the 57 bytes StructSize indicated.
+ */
+ if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
+ mb_put_uint8(mbp, 0);
+
+ /*
+ * Don't want to risk missing a successful
+ * open response, or we could "leak" FIDs.
+ */
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+ error = smb2_rq_simple_timed(rqp, smb2_timo_open);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2/3 Create Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 89 */
+ error = md_get_uint16le(mdp, &StructSize);
+ if (StructSize != 89) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint8(mdp, NULL); /* oplock lvl granted */
+ md_get_uint8(mdp, NULL); /* mbz */
+ md_get_uint32le(mdp, &createact); /* create_action */
+ md_get_uint64le(mdp, &llongint); /* creation time */
+ smb_time_NT2local(llongint, &fa.fa_createtime);
+ md_get_uint64le(mdp, &llongint); /* access time */
+ smb_time_NT2local(llongint, &fa.fa_atime);
+ md_get_uint64le(mdp, &llongint); /* write time */
+ smb_time_NT2local(llongint, &fa.fa_mtime);
+ md_get_uint64le(mdp, &llongint); /* change time */
+ smb_time_NT2local(llongint, &fa.fa_ctime);
+ md_get_uint64le(mdp, &llongint); /* allocation size */
+ fa.fa_allocsz = llongint;
+ md_get_uint64le(mdp, &llongint); /* EOF position */
+ fa.fa_size = llongint;
+ md_get_uint32le(mdp, &longint); /* attributes */
+ fa.fa_attr = longint;
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /* Get SMB 2/3 File ID and create user fid to return */
+ md_get_uint64le(mdp, &smb2_fid.fid_persistent);
+ error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
+ if (error)
+ goto out;
+
+ /* Get Context Offset */
+ error = md_get_uint32le(mdp, &rcc_off);
+ if (error)
+ goto out;
+ /* Get Context Length */
+ error = md_get_uint32le(mdp, &rcc_len);
+ if (error)
+ goto out;
+
+ /*
+ * If the caller wants the returned create contexts, parse.
+ * Context offset is from the beginning of SMB 2/3 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 88
+ */
+ if (rcc_len != 0) {
+ int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ if (cctx_out != NULL) {
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, rcc_len, &m);
+ if (error)
+ goto out;
+ md_initm(cctx_out, m);
+ }
+ }
+
+out:
+ smb_rq_done(rqp);
+ if (error)
+ return (error);
+
+ *fidp = smb2_fid;
+ if (cr_act_p)
+ *cr_act_p = createact;
+ if (fap)
+ *fap = fa; /* struct copy */
+
+ return (0);
+}
+
+int
+smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2/3 Close Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 24); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Flags */
+ mb_put_uint32le(mbp, 0); /* Reserved */
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ /* Make sure we send, but only if already connected */
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
+ error = smb2_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_ioctl(
+ struct smb_share *ssp,
+ smb2fid_t *fid,
+ struct mbchain *data_in,
+ struct mdchain *data_out,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t ctl_code,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t *data_in_offp;
+ uint32_t *data_in_lenp;
+ uint32_t data_out_off;
+ uint32_t data_out_len;
+ uint16_t length = 0;
+ uint_t off, len;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 IOCTL Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 57); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, ctl_code);
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ data_in_offp = mb_reserve(mbp, 4);
+ data_in_lenp = mb_reserve(mbp, 4);
+ mb_put_uint32le(mbp, 0); /* Max input resp */
+
+ mb_put_uint32le(mbp, 0); /* Output offset */
+ mb_put_uint32le(mbp, 0); /* Output count */
+ mb_put_uint32le(mbp, *data_out_sz);
+
+ mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
+ mb_put_uint32le(mbp, 0); /* Reserved2 */
+
+ /*
+ * Now data_in (if provided)
+ */
+ if (data_in != NULL) {
+ off = mbp->mb_count;
+ *data_in_offp = htolel((uint32_t)off);
+ mb_put_mbchain(mbp, data_in);
+ len = mbp->mb_count - off;
+ *data_in_lenp = htolel((uint32_t)len);
+ } else {
+ *data_in_offp = 0;
+ *data_in_lenp = 0;
+ }
+
+ /*
+ * Run the request
+ */
+ error = smb2_rq_simple_timed(rqp, smb2_timo_default);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2 Ioctl Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 49 */
+ md_get_uint16le(mdp, &length);
+ if (length != 49) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* reserved */
+ md_get_uint32le(mdp, NULL); /* Get CtlCode */
+ md_get_uint64le(mdp, NULL); /* fid_persistent */
+ md_get_uint64le(mdp, NULL); /* fid_volatile */
+ md_get_uint32le(mdp, NULL); /* Get Input offset */
+ md_get_uint32le(mdp, NULL); /* Get Input count */
+
+ error = md_get_uint32le(mdp, &data_out_off);
+ if (error)
+ goto out;
+ error = md_get_uint32le(mdp, &data_out_len);
+ if (error)
+ goto out;
+
+ md_get_uint32le(mdp, NULL); /* Flags */
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /*
+ * If the caller wants the ioctl output data, parse.
+ * Current offset is: SMB2_HDRLEN + 48
+ * Always return the received length.
+ */
+ *data_out_sz = data_out_len;
+ if (data_out_len != 0) {
+ int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ if (data_out != NULL) {
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, data_out_len, &m);
+ if (error)
+ goto out;
+ md_initm(data_out, m);
+ }
+ }
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+int
+smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+ uint64_t off64 = uiop->uio_loffset;
+ uint32_t rlen;
+ uint16_t length = 0;
+ uint8_t data_offset;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Read Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 49); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Padding and Reserved */
+
+ mb_put_uint32le(mbp, *lenp); /* Length of read */
+ mb_put_uint64le(mbp, off64); /* Offset */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint32le(mbp, 1); /* MinCount */
+ /* (only indicates blocking) */
+
+ mb_put_uint32le(mbp, 0); /* Channel */
+ mb_put_uint32le(mbp, 0); /* Remaining */
+ mb_put_uint32le(mbp, 0); /* Channel offset/len */
+ mb_put_uint8(mbp, 0); /* data "blob" (pad) */
+
+ if (timo == 0)
+ timo = smb2_timo_read;
+ error = smb2_rq_simple_timed(rqp, timo);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2 Read Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 17 */
+ md_get_uint16le(mdp, &length);
+ if (length != 17) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint8(mdp, &data_offset);
+ md_get_uint8(mdp, NULL); /* reserved */
+
+ /* Get Data Length read */
+ error = md_get_uint32le(mdp, &rlen);
+ if (error)
+ goto out;
+
+ md_get_uint32le(mdp, NULL); /* Data Remaining (always 0) */
+ md_get_uint32le(mdp, NULL); /* Get Reserved2 (always 0) */
+
+ /*
+ * Data offset is from the beginning of SMB 2/3 Header
+ * Calculate how much further we have to go to get to it.
+ */
+ if (data_offset < (SMB2_HDRLEN + 16)) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (data_offset > (SMB2_HDRLEN + 16)) {
+ int skip = data_offset - (SMB2_HDRLEN + 16);
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Get the data
+ */
+ if (rlen == 0) {
+ *lenp = rlen;
+ goto out;
+ }
+ /* paranoid */
+ if (rlen > *lenp) {
+ SMBSDEBUG("bad server! rlen %d, len %d\n",
+ rlen, *lenp);
+ rlen = *lenp;
+ }
+
+ error = md_get_uio(mdp, uiop, rlen);
+ if (error)
+ goto out;
+
+ /* Success */
+ *lenp = rlen;
+
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+ uint64_t off64 = uiop->uio_loffset;
+ uint32_t rlen;
+ uint16_t data_offset;
+ uint16_t length = 0;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Write Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 49); /* Struct size */
+ data_offset = SMB2_HDRLEN + 48;
+ mb_put_uint16le(mbp, data_offset); /* Data Offset */
+ mb_put_uint32le(mbp, *lenp); /* Length of write */
+ mb_put_uint64le(mbp, off64); /* Offset */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint32le(mbp, 0); /* Channel */
+ mb_put_uint32le(mbp, 0); /* Remaining */
+ mb_put_uint32le(mbp, 0); /* Channel offset/len */
+ mb_put_uint32le(mbp, 0); /* Write flags */
+
+ error = mb_put_uio(mbp, uiop, *lenp);
+ if (error)
+ goto out;
+
+ if (timo == 0)
+ timo = smb2_timo_write;
+ error = smb2_rq_simple_timed(rqp, timo);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2/3 Write Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 17 */
+ md_get_uint16le(mdp, &length);
+ if (length != 17) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint16le(mdp, NULL); /* Get Reserved */
+
+ /* Get Data Length written */
+ error = md_get_uint32le(mdp, &rlen);
+ if (error)
+ goto out;
+
+ /* Get Data Remaining (always 0) */
+ md_get_uint32le(mdp, NULL);
+
+ /* Get Reserved2 (always 0) */
+ md_get_uint32le(mdp, NULL);
+
+ /* Success */
+ *lenp = rlen;
+
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb2_rq_internal)
+ */
+int
+smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Echo Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_internal(rqp, timo);
+
+ smb_rq_done(rqp);
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
index d1e7efd60a..398be59709 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -34,6 +34,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -61,6 +63,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
@@ -80,6 +83,9 @@ static void smb_vc_gone(struct smb_connobj *cp);
static void smb_share_free(struct smb_connobj *cp);
static void smb_share_gone(struct smb_connobj *cp);
+static void smb_fh_free(struct smb_connobj *cp);
+static void smb_fh_gone(struct smb_connobj *cp);
+
int
smb_sm_init(void)
{
@@ -105,7 +111,7 @@ void
smb_sm_done(void)
{
/*
- * XXX Q4BP why are we not iterating on smb_vclist here?
+ * Why are we not iterating on smb_vclist here?
* Because the caller has just called smb_sm_idle() to
* make sure we have no VCs before calling this.
*/
@@ -181,6 +187,16 @@ smb_co_rele(struct smb_connobj *co)
int old_flags;
SMB_CO_LOCK(co);
+
+ /*
+ * When VC usecount goes from 2 to 1, signal the iod_idle CV.
+ * It's unfortunate to have object type-specific logic here,
+ * but it's hard to do this anywhere else.
+ */
+ if (co->co_level == SMBL_VC && co->co_usecount == 2) {
+ smb_vc_t *vcp = CPTOVC(co);
+ cv_signal(&vcp->iod_idle);
+ }
if (co->co_usecount > 1) {
co->co_usecount--;
SMB_CO_UNLOCK(co);
@@ -365,10 +381,12 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_mackey != NULL)
kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ if (vcp->vc_ssnkey != NULL)
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ cv_destroy(&vcp->iod_muxwait);
cv_destroy(&vcp->iod_idle);
rw_destroy(&vcp->iod_rqlock);
- sema_destroy(&vcp->vc_sendlock);
cv_destroy(&vcp->vc_statechg);
smb_co_done(VCTOCP(vcp));
kmem_free(vcp, sizeof (*vcp));
@@ -392,14 +410,15 @@ smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
vcp->vc_co.co_gone = smb_vc_gone;
cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
- sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+ cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
/* Expanded TAILQ_HEAD_INITIALIZER */
vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
- vcp->vc_state = SMBIOD_ST_IDLE;
+ /* A brand new VC should connect. */
+ vcp->vc_state = SMBIOD_ST_RECONNECT;
/*
* These identify the connection.
@@ -612,10 +631,14 @@ smb_share_gone(struct smb_connobj *cp)
{
struct smb_cred scred;
struct smb_share *ssp = CPTOSS(cp);
+ smb_vc_t *vcp = SSTOVC(ssp);
smb_credinit(&scred, NULL);
smb_iod_shutdown_share(ssp);
- (void) smb_smb_treedisconnect(ssp, &scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ (void) smb2_smb_treedisconnect(ssp, &scred);
+ else
+ (void) smb_smb_treedisconnect(ssp, &scred);
smb_credrele(&scred);
}
@@ -655,6 +678,7 @@ smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
ssp->ss_tid = SMB_TID_UNKNOWN;
+ ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
bcopy(&tcon->tc_sh, &ssp->ss_ioc,
sizeof (smbioc_oshare_t));
@@ -770,6 +794,7 @@ smb_share_invalidate(struct smb_share *ssp)
int
smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
{
+ smb_vc_t *vcp = SSTOVC(ssp);
clock_t tmo;
int error;
@@ -813,7 +838,10 @@ smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
* and ss_flags |= SMBS_CONNECTED;
*/
SMB_SS_UNLOCK(ssp);
- error = smb_smb_treeconnect(ssp, scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ error = smb2_smb_treeconnect(ssp, scred);
+ else
+ error = smb_smb_treeconnect(ssp, scred);
SMB_SS_LOCK(ssp);
ssp->ss_flags &= ~SMBS_RECONNECTING;
@@ -829,6 +857,114 @@ out:
}
/*
+ * File handle level functions
+ */
+
+void
+smb_fh_hold(struct smb_fh *fhp)
+{
+ smb_co_hold(FHTOCP(fhp));
+}
+
+void
+smb_fh_rele(struct smb_fh *fhp)
+{
+ smb_co_rele(FHTOCP(fhp));
+}
+
+void
+smb_fh_close(struct smb_fh *fhp)
+{
+ smb_co_kill(FHTOCP(fhp));
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_fh_kill()
+ */
+static void
+smb_fh_gone(struct smb_connobj *cp)
+{
+ struct smb_cred scred;
+ struct smb_fh *fhp = CPTOFH(cp);
+ smb_share_t *ssp = FHTOSS(fhp);
+ int err;
+
+ if ((fhp->fh_flags & SMBFH_VALID) == 0)
+ return;
+
+ /*
+ * We have no durable handles (yet) so if there has been a
+ * reconnect, don't bother to close this handle.
+ */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return;
+
+ smb_credinit(&scred, NULL);
+ err = smb_smb_close(ssp, fhp, &scred);
+ smb_credrele(&scred);
+ if (err) {
+ SMBSDEBUG("close err=%d\n", err);
+ }
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_fh_free(struct smb_connobj *cp)
+{
+ struct smb_fh *fhp = CPTOFH(cp);
+
+ smb_co_done(FHTOCP(fhp));
+ kmem_free(fhp, sizeof (*fhp));
+}
+
+/*
+ * Allocate fh structure and attach it to the given share.
+ * Share expected to be locked on entry.
+ */
+/*ARGSUSED*/
+int
+smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
+{
+ static char objtype[] = "smb_fh";
+ struct smb_fh *fhp;
+
+ fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
+ smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
+ fhp->fh_co.co_free = smb_fh_free;
+ fhp->fh_co.co_gone = smb_fh_gone;
+
+ SMB_SS_LOCK(ssp);
+ if ((ssp->ss_flags & SMBS_GONE) != 0) {
+ SMB_SS_UNLOCK(ssp);
+ smb_fh_free(FHTOCP(fhp));
+ return (ENOTCONN);
+ }
+
+ smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
+ *fhpp = fhp;
+ SMB_SS_UNLOCK(ssp);
+
+ return (0);
+}
+
+void
+smb_fh_opened(struct smb_fh *fhp)
+{
+ smb_share_t *ssp = FHTOSS(fhp);
+
+ SMB_FH_LOCK(fhp);
+ fhp->fh_vcgenid = ssp->ss_vcgenid;
+ fhp->fh_flags |= SMBFH_VALID;
+ SMB_FH_UNLOCK(fhp);
+}
+
+
+/*
* Solaris zones support
*/
/*ARGSUSED*/
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
index 42dfd687f9..d0a8a1dca0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -33,9 +33,11 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_CONN_H
@@ -46,6 +48,7 @@
#include <sys/queue.h> /* for SLIST below */
#include <sys/uio.h>
#include <netsmb/smb_dev.h>
+#include "smb_signing.h"
/*
* Credentials of user/process for processing in the connection procedures
@@ -61,14 +64,14 @@ typedef struct smb_cred {
/*
* Bits in vc_flags (a.k.a. vc_co.co_flags)
- * Many of these were duplicates of SMBVOPT_ flags
- * and we now keep those too instead of merging
- * them into vc_flags.
+ * Note: SMBO_GONE is also in vc_flags
*/
-
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
+#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
+#define SMBV_SIGNING 0x0100 /* negotiated signing */
+#define SMBV_SMB2 0x0200 /* VC using SMB 2 or 3 */
+#define SMBV_HAS_FILEIDS 0x0400 /* Use File IDs for hash and inode numbers */
+#define SMBV_NO_WRITE_THRU 0x0800 /* Can't use ... */
/*
* Note: the common "obj" level uses this GONE flag by
@@ -89,6 +92,16 @@ typedef struct smb_cred {
*/
#define SMBS_GONE SMBO_GONE
+/*
+ * bits in smb_fh fh_flags (a.k.a. ss_co.co_flags)
+ */
+#define SMBFH_VALID 0x0002 /* FID is valid */
+/*
+ * Note: the common "obj" level uses this GONE flag by
+ * the name SMBO_GONE. Keep this alias as a reminder.
+ */
+#define SMBFH_GONE SMBO_GONE
+
struct smb_rq;
/* This declares struct smb_rqhead */
TAILQ_HEAD(smb_rqhead, smb_rq);
@@ -141,9 +154,57 @@ typedef struct smb_connobj smb_connobj_t;
/*
* "Level" in the connection object hierarchy
*/
-#define SMBL_SM 0
-#define SMBL_VC 1
-#define SMBL_SHARE 2
+enum smbco_level {
+ SMBL_SM = 0,
+ SMBL_VC = 1,
+ SMBL_SHARE = 2,
+ SMBL_FH = 3
+};
+
+/*
+ * SMB1 Negotiated protocol parameters
+ */
+struct smb_sopt {
+ int16_t sv_proto; /* protocol dialect */
+ uchar_t sv_sm; /* security mode */
+ int16_t sv_tz; /* offset in min relative to UTC */
+ uint16_t sv_maxmux; /* max number of outstanding rq's */
+ uint16_t sv_maxvcs; /* max number of VCs */
+ uint16_t sv_rawmode;
+ uint32_t sv_maxtx; /* maximum transmit buf size */
+ uint32_t sv_maxraw; /* maximum raw-buffer size */
+ uint32_t sv_skey; /* session key */
+ uint32_t sv_caps; /* capabilites SMB_CAP_ */
+
+ /* SMB2+ fields */
+ uint32_t sv2_sessflags; /* final session setup reply flags */
+ uint16_t sv2_dialect; /* dialect (non zero for SMB 2/3 */
+ uint32_t sv2_capabilities; /* capabilities */
+ uint32_t sv2_maxtransact; /* max transact size */
+ uint32_t sv2_maxread; /* max read size */
+ uint32_t sv2_maxwrite; /* max write size */
+ uint8_t sv2_guid[16]; /* GUID */
+ uint16_t sv2_security_mode; /* security mode */
+};
+typedef struct smb_sopt smb_sopt_t;
+
+/*
+ * SMB1 I/O Deamon state
+ */
+struct smb_iods {
+ uint8_t is_hflags; /* SMB header flags */
+ uint16_t is_hflags2; /* SMB header flags2 */
+ uint16_t is_smbuid; /* SMB header UID */
+ uint16_t is_next_mid; /* SMB header MID */
+ uint32_t is_txmax; /* max tx/rx packet size */
+ uint32_t is_rwmax; /* max read/write data size */
+ uint32_t is_rxmax; /* max readx data size */
+ uint32_t is_wxmax; /* max writex data size */
+ /* Signing state */
+ uint32_t is_next_seq; /* my next sequence number */
+
+};
+typedef struct smb_iods smb_iods_t;
/*
* Virtual Circuit to a server (really connection + session).
@@ -160,20 +221,35 @@ typedef struct smb_vc {
uid_t vc_owner; /* Unix owner */
int vc_genid; /* "generation" ID */
- int vc_mackeylen; /* length of MAC key */
- uint8_t *vc_mackey; /* MAC key */
+ int vc_mackeylen; /* MAC key length */
+ int vc_ssnkeylen; /* session key length */
+ uint8_t *vc_mackey; /* MAC key buffer */
+ uint8_t *vc_ssnkey; /* session key buffer */
+ smb_sign_mech_t vc_signmech;
- ksema_t vc_sendlock;
struct smb_tran_desc *vc_tdesc; /* transport ops. vector */
void *vc_tdata; /* transport control block */
- kcondvar_t iod_idle; /* IOD thread idle CV */
+ /* SMB2+ fields */
+ uint64_t vc2_oldest_message_id;
+ uint64_t vc2_next_message_id;
+ uint64_t vc2_limit_message_id;
+ uint64_t vc2_session_id; /* session id */
+ uint64_t vc2_prev_session_id; /* for reconnect */
+ uint32_t vc2_lease_key; /* lease key gen */
+
+ kcondvar_t iod_idle; /* IOD thread idle CV */
krwlock_t iod_rqlock; /* iod_rqlist */
- struct smb_rqhead iod_rqlist; /* list of outstanding reqs */
- struct _kthread *iod_thr; /* the IOD (reader) thread */
+ struct smb_rqhead iod_rqlist; /* list of active reqs */
+ struct _kthread *iod_thr; /* the IOD (reader) thread */
int iod_flags; /* see SMBIOD_* below */
- int iod_newrq; /* send needed (iod_rqlock) */
- int iod_muxfull; /* maxmux limit reached */
+ uint_t iod_muxcnt; /* num. active requests */
+ uint_t iod_muxwant; /* waiting to be active */
+ kcondvar_t iod_muxwait;
+ boolean_t iod_noresp; /* Logged "not responding" */
+
+ smb_iods_t vc_iods;
+ smb_sopt_t vc_sopt;
/* This is copied in/out when IOD enters/returns */
smbioc_ssn_work_t vc_work;
@@ -187,33 +263,40 @@ typedef struct smb_vc {
/* defines for members in vc_ssn */
#define vc_owner vc_ssn.ssn_owner
+#define vc_vopt vc_ssn.ssn_vopt
+#define vc_minver vc_ssn.ssn_minver
+#define vc_maxver vc_ssn.ssn_maxver
#define vc_srvname vc_ssn.ssn_srvname
#define vc_srvaddr vc_ssn.ssn_id.id_srvaddr
#define vc_domain vc_ssn.ssn_id.id_domain
#define vc_username vc_ssn.ssn_id.id_user
-#define vc_vopt vc_ssn.ssn_vopt
/* defines for members in vc_work */
-#define vc_sopt vc_work.wk_sopt
-#define vc_maxmux vc_work.wk_sopt.sv_maxmux
-#define vc_tran_fd vc_work.wk_iods.is_tran_fd
-#define vc_hflags vc_work.wk_iods.is_hflags
-#define vc_hflags2 vc_work.wk_iods.is_hflags2
-#define vc_smbuid vc_work.wk_iods.is_smbuid
-#define vc_next_mid vc_work.wk_iods.is_next_mid
-#define vc_txmax vc_work.wk_iods.is_txmax
-#define vc_rwmax vc_work.wk_iods.is_rwmax
-#define vc_rxmax vc_work.wk_iods.is_rxmax
-#define vc_wxmax vc_work.wk_iods.is_wxmax
-#define vc_ssn_key vc_work.wk_iods.is_ssn_key
-#define vc_next_seq vc_work.wk_iods.is_next_seq
-#define vc_u_mackey vc_work.wk_iods.is_u_mackey
-#define vc_u_maclen vc_work.wk_iods.is_u_maclen
+#define vc_cl_guid vc_work.wk_cl_guid
+
+/* defines for members in vc_sopt ? */
+#define vc_maxmux vc_sopt.sv_maxmux
+
+/* defines for members in vc_iods */
+#define vc_hflags vc_iods.is_hflags
+#define vc_hflags2 vc_iods.is_hflags2
+#define vc_smbuid vc_iods.is_smbuid
+#define vc_next_mid vc_iods.is_next_mid
+#define vc_txmax vc_iods.is_txmax
+#define vc_rwmax vc_iods.is_rwmax
+#define vc_rxmax vc_iods.is_rxmax
+#define vc_wxmax vc_iods.is_wxmax
+#define vc_next_seq vc_iods.is_next_seq
#define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock)
#define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock)
-#define SMB_UNICODE_STRINGS(vcp) ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE)
+#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
+#define VCTOCP(vcp) (&(vcp)->vc_co)
+
+#define SMB_UNICODE_STRINGS(vcp) \
+ (((vcp)->vc_flags & SMBV_SMB2) != 0 || \
+ ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0)
/* Bits in iod_flags */
#define SMBIOD_RUNNING 0x0001
@@ -231,6 +314,9 @@ typedef struct smb_share {
int ss_vcgenid; /* check VC generation ID */
uint16_t ss_tid; /* TID */
uint16_t ss_options; /* option support bits */
+ uint32_t ss2_tree_id;
+ uint32_t ss2_share_flags;
+ uint32_t ss2_share_caps;
smbioc_oshare_t ss_ioc;
} smb_share_t;
@@ -245,27 +331,47 @@ typedef struct smb_share {
#define SMB_SS_LOCK(ssp) mutex_enter(&(ssp)->ss_lock)
#define SMB_SS_UNLOCK(ssp) mutex_exit(&(ssp)->ss_lock)
-#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
-#define VCTOCP(vcp) (&(vcp)->vc_co)
-
#define CPTOSS(cp) ((struct smb_share *)((void *)(cp)))
-#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
#define SSTOCP(ssp) (&(ssp)->ss_co)
+#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
+
+typedef struct smb2fid {
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+} smb2fid_t;
+
+/*
+ * smb_fh struct describes an open file handle under some share.
+ */
+typedef struct smb_fh {
+ struct smb_connobj fh_co; /* keep first! See CPTOSS */
+ int fh_vcgenid; /* check VC generation ID */
+ uint32_t fh_rights; /* granted access */
+ smb2fid_t fh_fid2;
+ uint16_t fh_fid1;
+} smb_fh_t;
+
+#define fh_lock fh_co.co_lock
+#define fh_flags fh_co.co_flags
+
+#define SMB_FH_LOCK(fhp) mutex_enter(&(fhp)->fh_lock)
+#define SMB_FH_UNLOCK(fhp) mutex_exit(&(fhp)->fh_lock)
+
+#define CPTOFH(cp) ((struct smb_fh *)((void *)(cp)))
+#define FHTOCP(fhp) (&(fhp)->fh_co)
+#define FHTOSS(fhp) CPTOSS(((fhp)->fh_co.co_parent))
/*
* Call-back operations vector, so the netsmb module
* can notify smbfs about events affecting mounts.
* Installed in netsmb after smbfs loads.
+ * Note: smbfs only uses the fscb_discon hook.
*/
typedef struct smb_fscb {
/* Called when the VC has disconnected. */
void (*fscb_disconn)(smb_share_t *);
/* Called when the VC has reconnected. */
void (*fscb_connect)(smb_share_t *);
- /* Called when the server becomes unresponsive. */
- void (*fscb_down)(smb_share_t *);
- /* Called when the server is responding again. */
- void (*fscb_up)(smb_share_t *);
} smb_fscb_t;
/* Install the above vector, or pass NULL to clear it. */
void smb_fscb_set(smb_fscb_t *);
@@ -278,14 +384,14 @@ typedef struct smb_dev {
kmutex_t sd_lock;
struct smb_vc *sd_vc; /* Reference to VC */
struct smb_share *sd_share; /* Reference to share if any */
+ struct smb_fh *sd_fh; /* Reference to FH, if any */
int sd_level; /* SMBL_VC, ... */
int sd_vcgenid; /* Generation of share or VC */
int sd_poll; /* Future use */
int sd_flags; /* State of connection */
-#define NSMBFL_OPEN 0x0001
-#define NSMBFL_IOD 0x0002
-#define NSMBFL_IOCTL 0x0004
- int sd_smbfid; /* library read/write */
+#define NSMBFL_OPEN 0x0001 /* Device minor is open */
+#define NSMBFL_IOD 0x0004 /* Open by IOD */
+#define NSMBFL_IOCTL 0x0010 /* Serialize ioctl calls */
zoneid_t zoneid; /* Zone id */
} smb_dev_t;
@@ -300,6 +406,8 @@ int smb_dev2share(int fd, struct smb_share **sspp);
/*
* smb_usr.c
*/
+int smb_usr_ioctl(smb_dev_t *, int, intptr_t, int, cred_t *);
+
int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags);
@@ -319,7 +427,10 @@ int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
-int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags,
+ cred_t *cr);
+
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
/*
@@ -327,18 +438,23 @@ int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
*/
int smb_iod_create(smb_vc_t *vcp);
int smb_iod_destroy(smb_vc_t *vcp);
-int smb_iod_connect(smb_vc_t *vcp);
void smb_iod_disconnect(smb_vc_t *vcp);
-int smb_iod_addrq(struct smb_rq *rqp);
-int smb_iod_multirq(struct smb_rq *rqp);
+int smb2_iod_addrq(struct smb_rq *rqp);
+int smb1_iod_addrq(struct smb_rq *rqp);
+int smb1_iod_multirq(struct smb_rq *rqp);
int smb_iod_waitrq(struct smb_rq *rqp);
+int smb_iod_waitrq_int(struct smb_rq *rqp);
void smb_iod_removerq(struct smb_rq *rqp);
+int smb_iod_sendrecv(struct smb_rq *, int);
void smb_iod_shutdown_share(smb_share_t *ssp);
void smb_iod_sendall(smb_vc_t *);
-int smb_iod_recvall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *, boolean_t);
-int smb_iod_vc_work(smb_vc_t *, cred_t *);
+int nsmb_iod_connect(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr);
+int smb_iod_vc_work(smb_vc_t *, int, cred_t *);
int smb_iod_vc_idle(smb_vc_t *);
int smb_iod_vc_rcfail(smb_vc_t *);
int smb_iod_reconnect(smb_vc_t *);
@@ -381,4 +497,13 @@ void smb_share_kill(smb_share_t *ssp);
void smb_share_invalidate(smb_share_t *ssp);
int smb_share_tcon(smb_share_t *, smb_cred_t *);
+/*
+ * File handle level functions
+ */
+int smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp);
+void smb_fh_opened(struct smb_fh *fhp);
+void smb_fh_close(struct smb_fh *fhp);
+void smb_fh_hold(struct smb_fh *fhp);
+void smb_fh_rele(struct smb_fh *fhp);
+
#endif /* _SMB_CONN_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
index 489a1756ec..3f00ec24ed 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -61,35 +62,42 @@
#include <sys/modctl.h>
#include <sys/devops.h>
#include <sys/thread.h>
-#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/zone.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/mchain.h> /* for "htoles()" */
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_pass.h>
+#ifndef _KERNEL
+#include <libfknsmb.h>
+
+#define _init(v) nsmb_drv_init(v)
+#define _fini(v) nsmb_drv_fini(v)
+
+#endif /* _KERNEL */
+
#define NSMB_MIN_MINOR 1
#define NSMB_MAX_MINOR L_MAXMIN32
/* for version checks */
const uint32_t nsmb_version = NSMB_VERSION;
+/* for smb_nbst_create() */
+dev_t nsmb_dev_tcp = NODEV;
+dev_t nsmb_dev_tcp6 = NODEV;
+
static void *statep;
static major_t nsmb_major;
static minor_t last_minor = NSMB_MIN_MINOR;
-static dev_info_t *nsmb_dip;
static kmutex_t dev_lck;
-/* Zone support */
-zone_key_t nsmb_zone_key;
-extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
-extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
-
/*
* cb_ops device operations.
*/
@@ -99,6 +107,15 @@ static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp);
static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
+#ifdef _KERNEL
+
+static dev_info_t *nsmb_dip;
+
+/* Zone support */
+zone_key_t nsmb_zone_key;
+extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
+extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
+
/* smbfs cb_ops */
static struct cb_ops nsmb_cbops = {
nsmb_open, /* open */
@@ -160,10 +177,14 @@ static struct modlinkage nsmb_modlinkage = {
NULL
};
+#endif /* _KERNEL */
+
int
_init(void)
{
+#ifdef _KERNEL
int error;
+#endif /* _KERNEL */
(void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
@@ -176,12 +197,7 @@ _init(void)
/* Initialize password Key chain DB. */
smb_pkey_init();
- /* Time conversion stuff. */
- smb_time_init();
-
- /* Initialize crypto mechanisms. */
- smb_crypto_mech_init();
-
+#ifdef _KERNEL
zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
nsmb_zone_destroy);
@@ -200,6 +216,14 @@ _init(void)
return (error);
}
+#else /* _KERNEL */
+ streams_msg_init();
+ /* No attach, so need to set major. */
+ nsmb_major = 1;
+ /* And these, for smb_nbst_create() */
+ nsmb_dev_tcp = AF_INET;
+ nsmb_dev_tcp6 = AF_INET6;
+#endif /* _KERNEL */
return (0);
}
@@ -218,6 +242,7 @@ _fini(void)
if ((status = smb_pkey_idle()) != 0)
return (status);
+#ifdef _KERNEL
/*
* Remove the module. Do this before destroying things,
* to prevent new entrances while we're destorying.
@@ -227,9 +252,7 @@ _fini(void)
}
(void) zone_key_delete(nsmb_zone_key);
-
- /* Time conversion stuff. */
- smb_time_fini();
+#endif /* _KERNEL */
/* Destroy password Key chain DB. */
smb_pkey_fini();
@@ -242,6 +265,8 @@ _fini(void)
return (status);
}
+#ifdef _KERNEL
+
int
_info(struct modinfo *modinfop)
{
@@ -270,6 +295,7 @@ nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
static int
nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
+ major_t tmaj;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
@@ -294,6 +320,20 @@ nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
nsmb_major = ddi_name_to_major(NSMB_NAME);
+ /*
+ * We also need major numbers for t_kopen
+ */
+ tmaj = ddi_name_to_major("tcp");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp major?");
+ else
+ nsmb_dev_tcp = makedevice(tmaj, 0);
+ tmaj = ddi_name_to_major("tcp6");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp6 major?");
+ else
+ nsmb_dev_tcp6 = makedevice(tmaj, 0);
+
nsmb_dip = dip;
ddi_report_dev(dip);
return (DDI_SUCCESS);
@@ -315,6 +355,65 @@ nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
return (DDI_SUCCESS);
}
+#else /* _KERNEL */
+
+/*
+ * Wrappers for libfknsmb: ioctl, open, close, load
+ */
+
+/*ARGSUSED*/
+int
+nsmb_drv_ioctl(dev32_t dev32, int cmd, intptr_t arg, int flags)
+{
+ dev_t dev = expldev(dev32);
+ cred_t *cr = CRED();
+ int err;
+
+ err = nsmb_ioctl(dev, cmd, arg, flags, cr, NULL);
+ return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_open(dev32_t *dev32p, int flags, int otyp)
+{
+ dev_t dev = expldev(*dev32p);
+ int err;
+
+ err = nsmb_open(&dev, flags, otyp, CRED());
+ if (err == 0) {
+ /*
+ * We have NSMB_MAX_MINOR == L_MAXMIN32
+ * therefore cmpldev never fails.
+ */
+ VERIFY(cmpldev(dev32p, dev) != 0);
+ }
+ return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_close(dev32_t dev32, int flags, int otyp)
+{
+ dev_t dev = expldev(dev32);
+ int err;
+
+ err = nsmb_close(dev, flags, otyp, CRED());
+ return (err);
+}
+
+/*
+ * This function intentionally does nothing. It's used only to
+ * force libfknsmb to load at program start so one can set
+ * breakpoints etc. without debugger "force load" tricks.
+ */
+void
+nsmb_drv_load(void)
+{
+}
+
+#endif /* _KERNEL */
+
/*ARGSUSED*/
static int
nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
@@ -325,7 +424,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
sdp = ddi_get_soft_state(statep, getminor(dev));
if (sdp == NULL) {
- return (DDI_FAILURE);
+ return (EBADF);
}
if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
return (EBADF);
@@ -346,107 +445,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
* check the zone status here on every ioctl call.
*/
- /*
- * Serialize ioctl calls. The smb_usr_... functions
- * don't expect concurrent calls on a given sdp.
- */
- mutex_enter(&sdp->sd_lock);
- if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
- mutex_exit(&sdp->sd_lock);
- return (EBUSY);
- }
- sdp->sd_flags |= NSMBFL_IOCTL;
- mutex_exit(&sdp->sd_lock);
-
- err = 0;
- switch (cmd) {
- case SMBIOC_GETVERS:
- (void) ddi_copyout(&nsmb_version, (void *)arg,
- sizeof (nsmb_version), flags);
- break;
-
- case SMBIOC_FLAGS2:
- err = smb_usr_get_flags2(sdp, arg, flags);
- break;
-
- case SMBIOC_GETSSNKEY:
- err = smb_usr_get_ssnkey(sdp, arg, flags);
- break;
-
- case SMBIOC_DUP_DEV:
- err = smb_usr_dup_dev(sdp, arg, flags);
- break;
-
- case SMBIOC_REQUEST:
- err = smb_usr_simplerq(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_T2RQ:
- err = smb_usr_t2request(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_READ:
- case SMBIOC_WRITE:
- err = smb_usr_rw(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_NTCREATE:
- err = smb_usr_ntcreate(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_PRINTJOB:
- err = smb_usr_printjob(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_CLOSEFH:
- err = smb_usr_closefh(sdp, cr);
- break;
-
- case SMBIOC_SSN_CREATE:
- case SMBIOC_SSN_FIND:
- err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_SSN_KILL:
- case SMBIOC_SSN_RELE:
- err = smb_usr_drop_ssn(sdp, cmd);
- break;
-
- case SMBIOC_TREE_CONNECT:
- case SMBIOC_TREE_FIND:
- err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_TREE_KILL:
- case SMBIOC_TREE_RELE:
- err = smb_usr_drop_tree(sdp, cmd);
- break;
-
- case SMBIOC_IOD_WORK:
- err = smb_usr_iod_work(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_IOD_IDLE:
- case SMBIOC_IOD_RCFAIL:
- err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
- break;
-
- case SMBIOC_PK_ADD:
- case SMBIOC_PK_DEL:
- case SMBIOC_PK_CHK:
- case SMBIOC_PK_DEL_OWNER:
- case SMBIOC_PK_DEL_EVERYONE:
- err = smb_pkey_ioctl(cmd, arg, flags, cr);
- break;
-
- default:
- err = ENOTTY;
- break;
- }
-
- mutex_enter(&sdp->sd_lock);
- sdp->sd_flags &= ~NSMBFL_IOCTL;
- mutex_exit(&sdp->sd_lock);
+ err = smb_usr_ioctl(sdp, cmd, arg, flags, cr);
return (err);
}
@@ -491,7 +490,6 @@ found:
*dev = makedevice(nsmb_major, m);
mutex_exit(&dev_lck);
- sdp->sd_smbfid = -1;
sdp->sd_flags |= NSMBFL_OPEN;
sdp->zoneid = crgetzoneid(cr);
mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
@@ -529,14 +527,17 @@ nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
return (err);
}
+/*ARGSUSED*/
static int
nsmb_close2(smb_dev_t *sdp, cred_t *cr)
{
struct smb_vc *vcp;
struct smb_share *ssp;
+ struct smb_fh *fhp;
- if (sdp->sd_smbfid != -1)
- (void) smb_usr_closefh(sdp, cr);
+ fhp = sdp->sd_fh;
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
ssp = sdp->sd_share;
if (ssp != NULL)
@@ -566,8 +567,10 @@ nsmb_close2(smb_dev_t *sdp, cred_t *cr)
int
smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
{
+#ifdef _KERNEL
file_t *fp = NULL;
vnode_t *vp;
+#endif /* _KERNEL */
smb_dev_t *from_sdp;
dev_t dev;
int32_t ufd;
@@ -582,16 +585,24 @@ smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
*/
if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
return (EFAULT);
+#ifdef _KERNEL
if ((fp = getf(ufd)) == NULL)
return (EBADF);
/* rele fp below */
vp = fp->f_vnode;
dev = vp->v_rdev;
+#else /* _KERNEL */
+ /*
+ * No getf(ufd) -- ufd is really a dev32_t
+ */
+ dev = expldev((dev32_t)ufd);
+#endif /* _KERNEL */
if (dev == 0 || dev == NODEV ||
getmajor(dev) != nsmb_major) {
err = EINVAL;
goto out;
}
+
from_sdp = ddi_get_soft_state(statep, getminor(dev));
if (from_sdp == NULL) {
err = EINVAL;
@@ -609,8 +620,10 @@ smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
err = 0;
out:
+#ifdef _KERNEL
if (fp)
releasef(ufd);
+#endif /* _KERNEL */
return (err);
}
@@ -621,19 +634,27 @@ out:
int
smb_dev2share(int fd, struct smb_share **sspp)
{
+#ifdef _KERNEL
file_t *fp = NULL;
vnode_t *vp;
+#endif /* _KERNEL */
smb_dev_t *sdp;
smb_share_t *ssp;
dev_t dev;
int err;
+#ifdef _KERNEL
if ((fp = getf(fd)) == NULL)
return (EBADF);
/* rele fp below */
-
vp = fp->f_vnode;
dev = vp->v_rdev;
+#else /* _KERNEL */
+ /*
+ * No getf(ufd) -- fd is really a dev32_t
+ */
+ dev = expldev((dev32_t)fd);
+#endif /* _KERNEL */
if (dev == 0 || dev == NODEV ||
getmajor(dev) != nsmb_major) {
err = EINVAL;
@@ -660,7 +681,9 @@ smb_dev2share(int fd, struct smb_share **sspp)
err = 0;
out:
+#ifdef _KERNEL
if (fp)
releasef(fd);
+#endif /* _KERNEL */
return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
index db82fa0958..48c8ef591d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
@@ -35,6 +35,9 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifdef DEBUG
@@ -67,13 +70,26 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
-int smb_iod_send_echo(smb_vc_t *);
+/*
+ * SMB messages are up to 64K. Let's leave room for two.
+ * If we negotiate up to SMB2, increase these. XXX todo
+ */
+static int smb_tcpsndbuf = 0x20000;
+static int smb_tcprcvbuf = 0x20000;
+static int smb_connect_timeout = 10; /* seconds */
+
+static int smb1_iod_process(smb_vc_t *, mblk_t *);
+static int smb2_iod_process(smb_vc_t *, mblk_t *);
+static int smb_iod_send_echo(smb_vc_t *, cred_t *cr);
+static int smb_iod_logoff(struct smb_vc *vcp, cred_t *cr);
/*
* This is set/cleared when smbfs loads/unloads
@@ -93,7 +109,10 @@ smb_iod_share_disconnected(smb_share_t *ssp)
smb_share_invalidate(ssp);
- /* smbfs_dead() */
+ /*
+ * This is the only fscb hook smbfs currently uses.
+ * Replaces smbfs_dead() from Darwin.
+ */
if (fscb && fscb->fscb_disconn) {
fscb->fscb_disconn(ssp);
}
@@ -142,19 +161,22 @@ smb_iod_invrq(struct smb_vc *vcp)
/*
* Invalidate all outstanding requests for this connection
+ * Also wakeup iod_muxwant waiters.
*/
rw_enter(&vcp->iod_rqlock, RW_READER);
TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
}
rw_exit(&vcp->iod_rqlock);
+ cv_broadcast(&vcp->iod_muxwait);
}
/*
- * Called by smb_vc_rele, smb_vc_kill, and by the driver
- * close entry point if the IOD closes its dev handle.
+ * Called by smb_vc_rele/smb_vc_kill on last ref, and by
+ * the driver close function if the IOD closes its minor.
+ * In those cases, the caller should be the IOD thread.
*
- * Forcibly kill the connection and IOD.
+ * Forcibly kill the connection.
*/
void
smb_iod_disconnect(struct smb_vc *vcp)
@@ -170,139 +192,209 @@ smb_iod_disconnect(struct smb_vc *vcp)
}
SMB_VC_UNLOCK(vcp);
- /*
- * Let's be safe here and avoid doing any
- * call across the network while trying to
- * shut things down. If we just disconnect,
- * the server will take care of the logoff.
- */
SMB_TRAN_DISCONNECT(vcp);
}
/*
* Send one request.
*
+ * SMB1 only
+ *
* Called by _addrq (for internal requests)
* and _sendall (via _addrq, _multirq, _waitrq)
+ * Errors are reported via the smb_rq, using:
+ * smb_iod_rqprocessed(rqp, ...)
*/
-static int
-smb_iod_sendrq(struct smb_rq *rqp)
+static void
+smb1_iod_sendrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
mblk_t *m;
int error;
ASSERT(vcp);
- ASSERT(SEMA_HELD(&vcp->vc_sendlock));
- ASSERT(RW_READ_HELD(&vcp->iod_rqlock));
+ ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
/*
- * Note: Anything special for SMBR_INTERNAL here?
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
+ smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+ return;
}
-
/*
- * On the first send, set the MID and (maybe)
- * the signing sequence numbers. The increments
- * here are serialized by vc_sendlock
+ * Overwrite the SMB header with the assigned MID and
+ * (if we're signing) sign it.
*/
- if (rqp->sr_sendcnt == 0) {
+ smb_rq_fillhdr(rqp);
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ smb_rq_sign(rqp);
+ }
- rqp->sr_mid = vcp->vc_next_mid++;
+ /*
+ * The transport send consumes the message and we'd
+ * prefer to keep a copy, so dupmsg() before sending.
+ */
+ m = dupmsg(rqp->sr_rq.mb_top);
+ if (m == NULL) {
+ error = ENOBUFS;
+ goto fatal;
+ }
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- /*
- * We're signing requests and verifying
- * signatures on responses. Set the
- * sequence numbers of the request and
- * response here, used in smb_rq_verify.
- */
- rqp->sr_seqno = vcp->vc_next_seq++;
- rqp->sr_rseqno = vcp->vc_next_seq++;
- }
+#ifdef DTRACE_PROBE2
+ DTRACE_PROBE2(iod_sendrq,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+#endif
- /* Fill in UID, TID, MID, etc. */
- smb_rq_fillhdr(rqp);
+ error = SMB_TRAN_SEND(vcp, m);
+ m = 0; /* consumed by SEND */
- /*
- * Sign the message now that we're finally done
- * filling in the SMB header fields, etc.
- */
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
+ rqp->sr_lerror = error;
+ if (error == 0) {
+ SMBRQ_LOCK(rqp);
+ rqp->sr_flags |= SMBR_SENT;
+ rqp->sr_state = SMBRQ_SENT;
+ SMBRQ_UNLOCK(rqp);
+ return;
}
- if (rqp->sr_sendcnt++ >= 60/SMBSBTIMO) { /* one minute */
- smb_iod_rqprocessed(rqp, rqp->sr_lerror, SMBR_RESTART);
+ /*
+ * Transport send returned an error.
+ * Was it a fatal one?
+ */
+ if (SMB_TRAN_FATAL(vcp, error)) {
/*
- * If all attempts to send a request failed, then
- * something is seriously hosed.
+ * No further attempts should be made
*/
- return (ENOTCONN);
+ fatal:
+ SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
+ smb_iod_rqprocessed(rqp, error, SMBR_RESTART);
+ return;
}
+}
+
+/*
+ * Send one request.
+ *
+ * SMB2 only
+ *
+ * Called by _addrq (for internal requests)
+ * and _sendall (via _addrq, _multirq, _waitrq)
+ * Errors are reported via the smb_rq, using:
+ * smb_iod_rqprocessed(rqp, ...)
+ */
+static void
+smb2_iod_sendrq(struct smb_rq *rqp)
+{
+ struct smb_rq *c_rqp; /* compound */
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *top_m;
+ mblk_t *cur_m;
+ int error;
+
+ ASSERT(vcp);
+ ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
/*
- * Replaced m_copym() with Solaris copymsg() which does the same
- * work when we want to do a M_COPYALL.
- * m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, 0);
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- m = copymsg(rqp->sr_rq.mb_top);
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+ return;
+ }
-#ifdef DTRACE_PROBE
- DTRACE_PROBE2(smb_iod_sendrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
-#else
- SMBIODEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
-#endif
- m_dumpm(m);
+ /*
+ * Overwrite the SMB header with the assigned MID and
+ * (if we're signing) sign it. If there are compounded
+ * requests after the top one, do those too.
+ */
+ smb2_rq_fillhdr(rqp);
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ smb2_rq_sign(rqp);
+ }
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ smb2_rq_fillhdr(c_rqp);
+ if (c_rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ smb2_rq_sign(c_rqp);
+ }
+ c_rqp = c_rqp->sr2_compound_next;
+ }
- if (m != NULL) {
- error = SMB_TRAN_SEND(vcp, m);
- m = 0; /* consumed by SEND */
- } else
+ /*
+ * The transport send consumes the message and we'd
+ * prefer to keep a copy, so dupmsg() before sending.
+ * We also need this to build the compound message
+ * that we'll actually send. The message offset at
+ * the start of each compounded message should be
+ * eight-byte aligned. The caller preparing the
+ * compounded request has to take care of that
+ * before we get here and sign messages etc.
+ */
+ top_m = dupmsg(rqp->sr_rq.mb_top);
+ if (top_m == NULL) {
error = ENOBUFS;
+ goto fatal;
+ }
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ size_t len = msgdsize(top_m);
+ ASSERT((len & 7) == 0);
+ cur_m = dupmsg(c_rqp->sr_rq.mb_top);
+ if (cur_m == NULL) {
+ freemsg(top_m);
+ error = ENOBUFS;
+ goto fatal;
+ }
+ linkb(top_m, cur_m);
+ }
+
+ DTRACE_PROBE2(iod_sendrq,
+ (smb_rq_t *), rqp, (mblk_t *), top_m);
+
+ error = SMB_TRAN_SEND(vcp, top_m);
+ top_m = 0; /* consumed by SEND */
rqp->sr_lerror = error;
if (error == 0) {
SMBRQ_LOCK(rqp);
rqp->sr_flags |= SMBR_SENT;
rqp->sr_state = SMBRQ_SENT;
- if (rqp->sr_flags & SMBR_SENDWAIT)
- cv_broadcast(&rqp->sr_cond);
SMBRQ_UNLOCK(rqp);
- return (0);
+ return;
}
/*
- * Check for fatal errors
+ * Transport send returned an error.
+ * Was it a fatal one?
*/
if (SMB_TRAN_FATAL(vcp, error)) {
/*
* No further attempts should be made
*/
+ fatal:
SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
- return (ENOTCONN);
+ smb_iod_rqprocessed(rqp, error, SMBR_RESTART);
+ return;
}
- if (error)
- SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error);
-
-#ifdef APPLE
- /* If proc waiting on rqp was signaled... */
- if (smb_rq_intr(rqp))
- smb_iod_rqprocessed(rqp, EINTR, 0);
-#endif
-
- return (0);
}
+/*
+ * Receive one NetBIOS (or NBT over TCP) message. If none have arrived,
+ * wait up to SMB_NBTIMO (15 sec.) for one to arrive, and then if still
+ * none have arrived, return ETIME.
+ */
static int
-smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp)
+smb_iod_recvmsg(struct smb_vc *vcp, mblk_t **mpp)
{
mblk_t *m;
- uchar_t *hp;
int error;
top:
@@ -312,58 +404,50 @@ top:
goto top;
if (error)
return (error);
- ASSERT(m);
+ ASSERT(m != NULL);
- m = m_pullup(m, SMB_HDRLEN);
+ m = m_pullup(m, 4);
if (m == NULL) {
return (ENOSR);
}
- /*
- * Check the SMB header
- */
- hp = mtod(m, uchar_t *);
- if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
- m_freem(m);
- return (EPROTO);
- }
-
*mpp = m;
return (0);
}
/*
+ * How long should we keep around an unused VC (connection)?
+ * There's usually a good chance connections will be reused,
+ * so the default is to keep such connections for 5 min.
+ */
+#ifdef DEBUG
+int smb_iod_idle_keep_time = 60; /* seconds */
+#else
+int smb_iod_idle_keep_time = 300; /* seconds */
+#endif
+
+/*
* Process incoming packets
*
- * This is the "reader" loop, run by the IOD thread
- * while in state SMBIOD_ST_VCACTIVE. The loop now
- * simply blocks in the socket recv until either a
- * message arrives, or a disconnect.
+ * This is the "reader" loop, run by the IOD thread. Normally we're in
+ * state SMBIOD_ST_VCACTIVE here, but during reconnect we're called in
+ * other states with poll==TRUE
*
- * Any non-zero error means the IOD should terminate.
+ * A non-zero error return here causes the IOD work loop to terminate.
*/
int
-smb_iod_recvall(struct smb_vc *vcp)
+smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
{
- struct smb_rq *rqp;
mblk_t *m;
- uchar_t *hp;
- ushort_t mid;
int error = 0;
- int etime_count = 0; /* for "server not responding", etc. */
+ int etime_idle = 0; /* How many 15 sec. "ticks" idle. */
+ int etime_count = 0; /* ... and when we have requests. */
for (;;) {
/*
* Check whether someone "killed" this VC,
* or is asking the IOD to terminate.
*/
-
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- error = 0;
- break;
- }
-
if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
SMBIODEBUG("SHUTDOWN set\n");
/* This IOD thread will terminate. */
@@ -376,52 +460,88 @@ smb_iod_recvall(struct smb_vc *vcp)
}
m = NULL;
- error = smb_iod_recv1(vcp, &m);
+ error = smb_iod_recvmsg(vcp, &m);
+
+ /*
+ * Internal requests (reconnecting) call this in a loop
+ * (with poll==TRUE) until the request completes.
+ */
+ if (error == ETIME && poll)
+ break;
if (error == ETIME &&
vcp->iod_rqlist.tqh_first != NULL) {
+
/*
- * Nothing received for 15 seconds and
- * we have requests in the queue.
+ * Nothing received and requests waiting.
+ * Increment etime_count. If we were idle,
+ * skip the 1st tick, because we started
+ * waiting before there were any requests.
*/
- etime_count++;
+ if (etime_idle != 0) {
+ etime_idle = 0;
+ } else if (etime_count < INT16_MAX) {
+ etime_count++;
+ }
/*
- * Once, at 15 sec. notify callbacks
- * and print the warning message.
+ * ETIME and requests in the queue.
+ * The first time (at 15 sec.)
+ * Log an error (just once).
*/
- if (etime_count == 1) {
- /* Was: smb_iod_notify_down(vcp); */
- if (fscb && fscb->fscb_down)
- smb_vc_walkshares(vcp,
- fscb->fscb_down);
+ if (etime_count > 0 &&
+ vcp->iod_noresp == B_FALSE) {
+ vcp->iod_noresp = B_TRUE;
zprintf(vcp->vc_zoneid,
"SMB server %s not responding\n",
vcp->vc_srvname);
}
-
/*
- * At 30 sec. try sending an echo, and then
- * once a minute thereafter.
+ * At 30 sec. try sending an echo, which
+ * should cause some response.
*/
- if ((etime_count & 3) == 2) {
- (void) smb_iod_send_echo(vcp);
+ if (etime_count == 2) {
+ SMBIODEBUG("send echo\n");
+ (void) smb_iod_send_echo(vcp, CRED());
+ }
+ /*
+ * At 45 sec. give up on the connection
+ * and try to reconnect.
+ */
+ if (etime_count == 3) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ SMB_VC_UNLOCK(vcp);
+ SMB_TRAN_DISCONNECT(vcp);
+ break;
}
-
continue;
- } /* ETIME && requests in queue */
+ } /* ETIME and requests in the queue */
if (error == ETIME) {
/*
- * If the IOD thread holds the last reference
- * to this VC, let the IOD thread terminate.
+ * Nothing received and no active requests.
+ *
+ * If we've received nothing from the server for
+ * smb_iod_idle_keep_time seconds, and the IOD
+ * thread holds the last reference to this VC,
+ * move to state IDLE and drop the TCP session.
+ * The IDLE handler will destroy the VC unless
+ * vc_state goes to RECONNECT before then.
*/
- if (vcp->vc_co.co_usecount > 1)
+ etime_count = 0;
+ if (etime_idle < INT16_MAX)
+ etime_idle++;
+ if ((etime_idle * SMB_NBTIMO) <
+ smb_iod_idle_keep_time)
continue;
SMB_VC_LOCK(vcp);
if (vcp->vc_co.co_usecount == 1) {
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
SMB_VC_UNLOCK(vcp);
+ SMBIODEBUG("logoff & disconnect\n");
+ (void) smb_iod_logoff(vcp, CRED());
+ SMB_TRAN_DISCONNECT(vcp);
error = 0;
break;
}
@@ -431,91 +551,327 @@ smb_iod_recvall(struct smb_vc *vcp)
if (error) {
/*
- * The recv. above returned some error
- * we can't continue from i.e. ENOTCONN.
- * It's dangerous to continue here.
- * (possible infinite loop!)
- *
- * If we have requests enqueued, next
- * state is reconnecting, else idle.
+ * The recv above returned an error indicating
+ * that our TCP session is no longer usable.
+ * Disconnect the session and get ready to
+ * reconnect. If we have pending requests,
+ * move to state reconnect immediately;
+ * otherwise move to state IDLE until a
+ * request is issued on this VC.
*/
- int state;
SMB_VC_LOCK(vcp);
- state = (vcp->iod_rqlist.tqh_first != NULL) ?
- SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE;
- smb_iod_newstate(vcp, state);
+ if (vcp->iod_rqlist.tqh_first != NULL)
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ else
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
- error = 0;
+ SMB_TRAN_DISCONNECT(vcp);
break;
}
/*
* Received something. Yea!
*/
- if (etime_count) {
- etime_count = 0;
+ etime_count = 0;
+ etime_idle = 0;
+ /*
+ * If we just completed a reconnect after logging
+ * "SMB server %s not responding" then log OK now.
+ */
+ if (vcp->iod_noresp) {
+ vcp->iod_noresp = B_FALSE;
zprintf(vcp->vc_zoneid, "SMB server %s OK\n",
vcp->vc_srvname);
+ }
- /* Was: smb_iod_notify_up(vcp); */
- if (fscb && fscb->fscb_up)
- smb_vc_walkshares(vcp, fscb->fscb_up);
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ error = smb2_iod_process(vcp, m);
+ } else {
+ error = smb1_iod_process(vcp, m);
}
/*
- * Have an SMB packet. The SMB header was
- * checked in smb_iod_recv1().
- * Find the request...
+ * Reconnect calls this in a loop with poll=TRUE
+ * We've received a response, so break now.
*/
- hp = mtod(m, uchar_t *);
- /*LINTED*/
- mid = letohs(SMB_HDRMID(hp));
- SMBIODEBUG("mid %04x\n", (uint_t)mid);
+ if (poll) {
+ error = 0;
+ break;
+ }
+ }
- rw_enter(&vcp->iod_rqlock, RW_READER);
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+ return (error);
+}
- if (rqp->sr_mid != mid)
- continue;
+/*
+ * Have what should be an SMB1 reply. Check and parse the header,
+ * then use the message ID to find the request this belongs to and
+ * post it on that request.
+ *
+ * Returns an error if the reader should give up.
+ * To be safe, error if we read garbage.
+ */
+static int
+smb1_iod_process(smb_vc_t *vcp, mblk_t *m)
+{
+ struct mdchain md;
+ struct smb_rq *rqp;
+ uint8_t cmd, sig[4];
+ uint16_t mid;
+ int err, skip;
+
+ m = m_pullup(m, SMB_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
+
+ /*
+ * Note: Intentionally do NOT md_done(&md)
+ * because that would free the message and
+ * we just want to peek here.
+ */
+ md_initm(&md, m);
- DTRACE_PROBE2(smb_iod_recvrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
- m_dumpm(m);
+ /*
+ * Check the SMB header version and get the MID.
+ *
+ * The header version should be SMB1 except when we're
+ * doing SMB1-to-SMB2 negotiation, in which case we may
+ * see an SMB2 header with message ID=0 (only allowed in
+ * vc_state == SMBIOD_ST_CONNECTED -- negotiationg).
+ */
+ err = md_get_mem(&md, sig, 4, MB_MSYSTEM);
+ if (err)
+ return (err);
+ if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') {
+ goto bad_hdr;
+ }
+ switch (sig[0]) {
+ case SMB_HDR_V1: /* SMB1 */
+ md_get_uint8(&md, &cmd);
+ /* Skip to and get the MID. At offset 5 now. */
+ skip = SMB_HDR_OFF_MID - 5;
+ md_get_mem(&md, NULL, skip, MB_MSYSTEM);
+ err = md_get_uint16le(&md, &mid);
+ if (err)
+ return (err);
+ break;
+ case SMB_HDR_V2: /* SMB2+ */
+ if (vcp->vc_state == SMBIOD_ST_CONNECTED) {
+ /*
+ * No need to look, can only be
+ * MID=0, cmd=negotiate
+ */
+ cmd = SMB_COM_NEGOTIATE;
+ mid = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+ bad_hdr:
+ default:
+ SMBIODEBUG("Bad SMB hdr\n");
+ m_freem(m);
+ return (EPROTO);
+ }
- SMBRQ_LOCK(rqp);
- if (rqp->sr_rp.md_top == NULL) {
- md_initm(&rqp->sr_rp, m);
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_enter(&vcp->iod_rqlock, RW_READER);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+ if (rqp->sr_mid != mid)
+ continue;
+
+ DTRACE_PROBE2(iod_post_reply,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+ m_dumpm(m);
+
+ SMBRQ_LOCK(rqp);
+ if (rqp->sr_rp.md_top == NULL) {
+ md_initm(&rqp->sr_rp, m);
+ } else {
+ if (rqp->sr_flags & SMBR_MULTIPACKET) {
+ md_append_record(&rqp->sr_rp, m);
} else {
- if (rqp->sr_flags & SMBR_MULTIPACKET) {
- md_append_record(&rqp->sr_rp, m);
- } else {
- SMBRQ_UNLOCK(rqp);
- SMBSDEBUG("duplicate response %d "
- "(ignored)\n", mid);
- break;
- }
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
+ break;
}
- smb_iod_rqprocessed_LH(rqp, 0, 0);
- SMBRQ_UNLOCK(rqp);
- break;
}
+ smb_iod_rqprocessed_LH(rqp, 0, 0);
+ SMBRQ_UNLOCK(rqp);
+ break;
+ }
+ rw_exit(&vcp->iod_rqlock);
+
+ if (rqp == NULL) {
+ if (cmd != SMB_COM_ECHO) {
+ SMBSDEBUG("drop resp: MID 0x%04x\n", (uint_t)mid);
+ }
+ m_freem(m);
+ /*
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
+ */
+ }
+ return (0);
+}
+
+/*
+ * Have what should be an SMB2 reply. Check and parse the header,
+ * then use the message ID to find the request this belongs to and
+ * post it on that request.
+ *
+ * We also want to apply any credit grant in this reply now,
+ * rather than waiting for the owner to wake up.
+ */
+static int
+smb2_iod_process(smb_vc_t *vcp, mblk_t *m)
+{
+ struct mdchain md;
+ struct smb_rq *rqp;
+ uint8_t sig[4];
+ mblk_t *next_m = NULL;
+ uint64_t message_id, async_id;
+ uint32_t flags, next_cmd_off, status;
+ uint16_t command, credits_granted;
+ int err;
- if (rqp == NULL) {
- int cmd = SMB_HDRCMD(hp);
+top:
+ m = m_pullup(m, SMB2_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
- if (cmd != SMB_COM_ECHO)
- SMBSDEBUG("drop resp: mid %d, cmd %d\n",
- (uint_t)mid, cmd);
-/* smb_printrqlist(vcp); */
+ /*
+ * Note: Intentionally do NOT md_done(&md)
+ * because that would free the message and
+ * we just want to peek here.
+ */
+ md_initm(&md, m);
+
+ /*
+ * Check the SMB header. Must be SMB2
+ * (and later, could be SMB3 encrypted)
+ */
+ err = md_get_mem(&md, sig, 4, MB_MSYSTEM);
+ if (err)
+ return (err);
+ if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') {
+ goto bad_hdr;
+ }
+ switch (sig[0]) {
+ case SMB_HDR_V2:
+ break;
+ case SMB_HDR_V3E:
+ /*
+ * Todo: If encryption enabled, decrypt the message
+ * and restart processing on the cleartext.
+ */
+ /* FALLTHROUGH */
+ bad_hdr:
+ default:
+ SMBIODEBUG("Bad SMB2 hdr\n");
+ m_freem(m);
+ return (EPROTO);
+ }
+
+ /*
+ * Parse the rest of the SMB2 header,
+ * skipping what we don't need.
+ */
+ md_get_uint32le(&md, NULL); /* length, credit_charge */
+ md_get_uint32le(&md, &status);
+ md_get_uint16le(&md, &command);
+ md_get_uint16le(&md, &credits_granted);
+ md_get_uint32le(&md, &flags);
+ md_get_uint32le(&md, &next_cmd_off);
+ md_get_uint64le(&md, &message_id);
+ if (flags & SMB2_FLAGS_ASYNC_COMMAND) {
+ md_get_uint64le(&md, &async_id);
+ } else {
+ /* PID, TID (not needed) */
+ async_id = 0;
+ }
+
+ /*
+ * If this is a compound reply, split it.
+ * Next must be 8-byte aligned.
+ */
+ if (next_cmd_off != 0) {
+ if ((next_cmd_off & 7) != 0)
+ SMBIODEBUG("Misaligned next cmd\n");
+ else
+ next_m = m_split(m, next_cmd_off, 1);
+ }
+
+ /*
+ * Apply the credit grant
+ */
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+ vcp->vc2_limit_message_id += credits_granted;
+
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_downgrade(&vcp->iod_rqlock);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+ if (rqp->sr2_messageid != message_id)
+ continue;
+
+ DTRACE_PROBE2(iod_post_reply,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+ m_dumpm(m);
+
+ /*
+ * If this is an interim response, just save the
+ * async ID but don't wakup the request.
+ * Don't need SMBRQ_LOCK for this.
+ */
+ if (status == NT_STATUS_PENDING && async_id != 0) {
+ rqp->sr2_rspasyncid = async_id;
m_freem(m);
+ break;
}
- rw_exit(&vcp->iod_rqlock);
+ SMBRQ_LOCK(rqp);
+ if (rqp->sr_rp.md_top == NULL) {
+ md_initm(&rqp->sr_rp, m);
+ } else {
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
+ break;
+ }
+ smb_iod_rqprocessed_LH(rqp, 0, 0);
+ SMBRQ_UNLOCK(rqp);
+ break;
}
+ rw_exit(&vcp->iod_rqlock);
- return (error);
+ if (rqp == NULL) {
+ if (command != SMB2_ECHO) {
+ SMBSDEBUG("drop resp: MID %lld\n",
+ (long long)message_id);
+ }
+ m_freem(m);
+ /*
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
+ */
+ }
+
+ /*
+ * If we split a compound reply, continue with the
+ * next part of the compound.
+ */
+ if (next_m != NULL) {
+ m = next_m;
+ goto top;
+ }
+
+ return (0);
}
/*
@@ -529,126 +885,256 @@ smb_iod_recvall(struct smb_vc *vcp)
* The smb_smb_echo call uses SMBR_INTERNAL
* to avoid calling smb_iod_sendall().
*/
-int
-smb_iod_send_echo(smb_vc_t *vcp)
+static int
+smb_iod_send_echo(smb_vc_t *vcp, cred_t *cr)
{
smb_cred_t scred;
- int err;
+ int err, tmo = SMBNOREPLYWAIT;
- smb_credinit(&scred, NULL);
- err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT);
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ err = smb2_smb_echo(vcp, &scred, tmo);
+ } else {
+ err = smb_smb_echo(vcp, &scred, tmo);
+ }
smb_credrele(&scred);
return (err);
}
/*
- * The IOD thread is now just a "reader",
- * so no more smb_iod_request(). Yea!
+ * Helper for smb1_iod_addrq, smb2_iod_addrq
+ * Returns zero if interrupted, else 1.
*/
+static int
+smb_iod_muxwait(smb_vc_t *vcp, boolean_t sig_ok)
+{
+ int rc;
+
+ SMB_VC_LOCK(vcp);
+ vcp->iod_muxwant++;
+ if (sig_ok) {
+ rc = cv_wait_sig(&vcp->iod_muxwait, &vcp->vc_lock);
+ } else {
+ cv_wait(&vcp->iod_muxwait, &vcp->vc_lock);
+ rc = 1;
+ }
+ vcp->iod_muxwant--;
+ SMB_VC_UNLOCK(vcp);
+
+ return (rc);
+}
/*
- * Place request in the queue, and send it now if possible.
+ * Place request in the queue, and send it.
* Called with no locks held.
+ *
+ * Called for SMB1 only
+ *
+ * The logic for how we limit active requests differs between
+ * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt.
*/
int
-smb_iod_addrq(struct smb_rq *rqp)
+smb1_iod_addrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- int error, save_newrq;
+ uint16_t need;
+ boolean_t sig_ok =
+ (rqp->sr_flags & SMBR_NOINTR_SEND) == 0;
ASSERT(rqp->sr_cred);
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+ rqp->sr_owner = curthread;
+
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+
+recheck:
/*
- * State should be correct after the check in
- * smb_rq_enqueue(), but we dropped locks...
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ rw_exit(&vcp->iod_rqlock);
return (ENOTCONN);
}
/*
- * Requests from the IOD itself are marked _INTERNAL,
- * and get some special treatment to avoid blocking
- * the reader thread (so we don't deadlock).
- * The request is not yet on the queue, so we can
- * modify it's state here without locks.
- * Only thing using this now is ECHO.
+ * If we're at the limit of active requests, block until
+ * enough requests complete so we can make ours active.
+ * Wakeup in smb_iod_removerq().
+ *
+ * Normal callers leave one slot free, so internal
+ * callers can have the last slot if needed.
*/
- rqp->sr_owner = curthread;
- if (rqp->sr_owner == vcp->iod_thr) {
- rqp->sr_flags |= SMBR_INTERNAL;
-
- /*
- * This is a request from the IOD thread.
- * Always send directly from this thread.
- * Note lock order: iod_rqlist, vc_sendlock
- */
+ need = 1;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0)
+ need++;
+ if ((vcp->iod_muxcnt + need) > vcp->vc_maxmux) {
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp->sr_flags & SMBR_INTERNAL)
+ return (EBUSY);
+ if (smb_iod_muxwait(vcp, sig_ok) == 0)
+ return (EINTR);
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link);
- rw_downgrade(&vcp->iod_rqlock);
+ goto recheck;
+ }
- /*
- * Note: iod_sendrq expects vc_sendlock,
- * so take that here, but carefully:
- * Never block the IOD thread here.
- */
- if (sema_tryp(&vcp->vc_sendlock) == 0) {
- SMBIODEBUG("sendlock busy\n");
- error = EAGAIN;
- } else {
- /* Have vc_sendlock */
- error = smb_iod_sendrq(rqp);
- sema_v(&vcp->vc_sendlock);
- }
+ /*
+ * Add this request to the active list and send it.
+ * For SMB2 we may have a sequence of compounded
+ * requests, in which case we must add them all.
+ * They're sent as a compound in smb2_iod_sendrq.
+ */
+ rqp->sr_mid = vcp->vc_next_mid++;
+ /* If signing, set the signing sequence numbers. */
+ if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 &
+ SMB_FLAGS2_SECURITY_SIGNATURE) != 0) {
+ rqp->sr_seqno = vcp->vc_next_seq++;
+ rqp->sr_rseqno = vcp->vc_next_seq++;
+ }
+ vcp->iod_muxcnt++;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+ smb1_iod_sendrq(rqp);
- rw_exit(&vcp->iod_rqlock);
+ rw_exit(&vcp->iod_rqlock);
+ return (0);
+}
- /*
- * In the non-error case, _removerq
- * is done by either smb_rq_reply
- * or smb_iod_waitrq.
- */
- if (error)
- smb_iod_removerq(rqp);
+/*
+ * Place request in the queue, and send it.
+ * Called with no locks held.
+ *
+ * Called for SMB2 only.
+ *
+ * With SMB2 we have a range of valid message IDs, and we may
+ * only send requests when we can assign a message ID within
+ * the valid range. We may need to wait here for some active
+ * request to finish (and update vc2_limit_message_id) before
+ * we can get message IDs for our new request(s). Another
+ * difference is that the request sequence we're waiting to
+ * add here may require multipe message IDs, either due to
+ * either compounding or multi-credit requests. Therefore
+ * we need to wait for the availibility of how ever many
+ * message IDs are required by our request sequence.
+ */
+int
+smb2_iod_addrq(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_rq *c_rqp; /* compound req */
+ uint16_t charge;
+ boolean_t sig_ok =
+ (rqp->sr_flags & SMBR_NOINTR_SEND) == 0;
- return (error);
+ ASSERT(rqp->sr_cred != NULL);
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ /*
+ * Figure out the credit charges
+ * No multi-credit messages yet.
+ */
+ rqp->sr2_totalcreditcharge = rqp->sr2_creditcharge;
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ rqp->sr2_totalcreditcharge += c_rqp->sr2_creditcharge;
+ c_rqp = c_rqp->sr2_compound_next;
}
+ /*
+ * Internal request must not be compounded
+ * and should use exactly one credit.
+ */
+ if (rqp->sr_flags & SMBR_INTERNAL) {
+ if (rqp->sr2_compound_next != NULL) {
+ ASSERT(0);
+ return (EINVAL);
+ }
+ }
+
+ rqp->sr_owner = curthread;
+
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
- /* iod_rqlock/WRITER protects iod_newrq */
- save_newrq = vcp->iod_newrq;
- vcp->iod_newrq++;
+recheck:
+ /*
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
+ */
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ rw_exit(&vcp->iod_rqlock);
+ return (ENOTCONN);
+ }
- rw_exit(&vcp->iod_rqlock);
+ /*
+ * If we're at the limit of active requests, block until
+ * enough requests complete so we can make ours active.
+ * Wakeup in smb_iod_removerq().
+ *
+ * Normal callers leave one slot free, so internal
+ * callers can have the last slot if needed.
+ */
+ charge = rqp->sr2_totalcreditcharge;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0)
+ charge++;
+ if ((vcp->vc2_next_message_id + charge) >
+ vcp->vc2_limit_message_id) {
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp->sr_flags & SMBR_INTERNAL)
+ return (EBUSY);
+ if (smb_iod_muxwait(vcp, sig_ok) == 0)
+ return (EINTR);
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+ goto recheck;
+ }
/*
- * Now send any requests that need to be sent,
- * including the one we just put on the list.
- * Only the thread that found iod_newrq==0
- * needs to run the send loop.
+ * Add this request to the active list and send it.
+ * For SMB2 we may have a sequence of compounded
+ * requests, in which case we must add them all.
+ * They're sent as a compound in smb2_iod_sendrq.
*/
- if (save_newrq == 0)
- smb_iod_sendall(vcp);
+ rqp->sr2_messageid = vcp->vc2_next_message_id;
+ vcp->vc2_next_message_id += rqp->sr2_creditcharge;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ c_rqp->sr2_messageid = vcp->vc2_next_message_id;
+ vcp->vc2_next_message_id += c_rqp->sr2_creditcharge;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, c_rqp, sr_link);
+ c_rqp = c_rqp->sr2_compound_next;
+ }
+ smb2_iod_sendrq(rqp);
+
+ rw_exit(&vcp->iod_rqlock);
return (0);
}
/*
* Mark an SMBR_MULTIPACKET request as
* needing another send. Similar to the
- * "normal" part of smb_iod_addrq.
+ * "normal" part of smb1_iod_addrq.
+ * Only used by SMB1
*/
int
-smb_iod_multirq(struct smb_rq *rqp)
+smb1_iod_multirq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- int save_newrq;
ASSERT(rqp->sr_flags & SMBR_MULTIPACKET);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ ASSERT("!SMB2?");
+ return (EINVAL);
+ }
+
if (rqp->sr_flags & SMBR_INTERNAL)
return (EINVAL);
@@ -661,32 +1147,36 @@ smb_iod_multirq(struct smb_rq *rqp)
/* Already on iod_rqlist, just reset state. */
rqp->sr_state = SMBRQ_NOTSENT;
-
- /* iod_rqlock/WRITER protects iod_newrq */
- save_newrq = vcp->iod_newrq;
- vcp->iod_newrq++;
+ smb1_iod_sendrq(rqp);
rw_exit(&vcp->iod_rqlock);
- /*
- * Now send any requests that need to be sent,
- * including the one we just marked NOTSENT.
- * Only the thread that found iod_newrq==0
- * needs to run the send loop.
- */
- if (save_newrq == 0)
- smb_iod_sendall(vcp);
-
return (0);
}
-
+/*
+ * Remove a request from the active list, and
+ * wake up requests waiting to go active.
+ *
+ * Shared by SMB1 + SMB2
+ *
+ * The logic for how we limit active requests differs between
+ * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt.
+ * With SMB2 we have a range of valid message IDs, and when we
+ * retire the oldest request we need to keep track of what is
+ * now the oldest message ID. In both cases, after we take a
+ * request out of the list here, we should be able to wake up
+ * a request waiting to get in the active list.
+ */
void
smb_iod_removerq(struct smb_rq *rqp)
{
+ struct smb_rq *rqp2;
struct smb_vc *vcp = rqp->sr_vc;
+ boolean_t was_head = B_FALSE;
rw_enter(&vcp->iod_rqlock, RW_WRITER);
+
#ifdef QUEUEDEBUG
/*
* Make sure we have not already removed it.
@@ -695,30 +1185,47 @@ smb_iod_removerq(struct smb_rq *rqp)
*/
ASSERT(rqp->sr_link.tqe_next != (void *)1L);
#endif
+
+ if (TAILQ_FIRST(&vcp->iod_rqlist) == rqp)
+ was_head = B_TRUE;
TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link);
- rw_exit(&vcp->iod_rqlock);
-}
+ if (vcp->vc_flags & SMBV_SMB2) {
+ rqp2 = TAILQ_FIRST(&vcp->iod_rqlist);
+ if (was_head && rqp2 != NULL) {
+ /* Do we still need this? */
+ vcp->vc2_oldest_message_id =
+ rqp2->sr2_messageid;
+ }
+ } else {
+ ASSERT(vcp->iod_muxcnt > 0);
+ vcp->iod_muxcnt--;
+ }
+ rw_exit(&vcp->iod_rqlock);
+ /*
+ * If there are requests waiting for "mux" slots,
+ * wake one.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->iod_muxwant != 0)
+ cv_signal(&vcp->iod_muxwait);
+ SMB_VC_UNLOCK(vcp);
+}
/*
* Wait for a request to complete.
- *
- * For normal requests, we need to deal with
- * ioc_muxcnt dropping below vc_maxmux by
- * making arrangements to send more...
*/
int
smb_iod_waitrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
clock_t tr, tmo1, tmo2;
- int error, rc;
+ int error;
if (rqp->sr_flags & SMBR_INTERNAL) {
- ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
- smb_iod_removerq(rqp);
- return (EAGAIN);
+ /* XXX - Do we ever take this path now? */
+ return (smb_iod_waitrq_int(rqp));
}
/*
@@ -730,35 +1237,6 @@ smb_iod_waitrq(struct smb_rq *rqp)
SMBRQ_LOCK(rqp);
/*
- * First, wait for the request to be sent. Normally the send
- * has already happened by the time we get here. However, if
- * we have more than maxmux entries in the request list, our
- * request may not be sent until other requests complete.
- * The wait in this case is due to local I/O demands, so
- * we don't want the server response timeout to apply.
- *
- * If a request is allowed to interrupt this wait, then the
- * request is cancelled and never sent OTW. Some kinds of
- * requests should never be cancelled (i.e. close) and those
- * are marked SMBR_NOINTR_SEND so they either go eventually,
- * or a connection close will terminate them with ENOTCONN.
- */
- while (rqp->sr_state == SMBRQ_NOTSENT) {
- rqp->sr_flags |= SMBR_SENDWAIT;
- if (rqp->sr_flags & SMBR_NOINTR_SEND) {
- cv_wait(&rqp->sr_cond, &rqp->sr_lock);
- rc = 1;
- } else
- rc = cv_wait_sig(&rqp->sr_cond, &rqp->sr_lock);
- rqp->sr_flags &= ~SMBR_SENDWAIT;
- if (rc == 0) {
- SMBIODEBUG("EINTR in sendwait, rqp=%p\n", rqp);
- error = EINTR;
- goto out;
- }
- }
-
- /*
* The request has been sent. Now wait for the response,
* with the timeout specified for this request.
* Compute all the deadlines now, so we effectively
@@ -791,17 +1269,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq1,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (still waiting).\n", vcp->vc_srvname,
- rqp->sr_mid, smb_timo_notice);
-#endif
}
}
@@ -820,17 +1289,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq2,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (giving up).\n", vcp->vc_srvname,
- rqp->sr_mid, rqp->sr_timo);
-#endif
error = ETIME;
goto out;
}
@@ -849,13 +1309,34 @@ out:
if ((rqp->sr_flags & SMBR_MULTIPACKET) == 0)
smb_iod_removerq(rqp);
- /*
- * Some request has been completed.
- * If we reached the mux limit,
- * re-run the send loop...
- */
- if (vcp->iod_muxfull)
- smb_iod_sendall(vcp);
+ return (error);
+}
+
+/*
+ * Internal variant of smb_iod_waitrq(), for use in
+ * requests run by the IOD (reader) thread itself.
+ * Block only long enough to receive one reply.
+ */
+int
+smb_iod_waitrq_int(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int timeleft = rqp->sr_timo;
+ int error;
+
+ ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
+again:
+ error = smb_iod_recvall(vcp, B_TRUE);
+ if (error == ETIME) {
+ /* We waited SMB_NBTIMO sec. */
+ timeleft -= SMB_NBTIMO;
+ if (timeleft > 0)
+ goto again;
+ }
+
+ smb_iod_removerq(rqp);
+ if (rqp->sr_state != SMBRQ_NOTIFIED)
+ error = ETIME;
return (error);
}
@@ -885,79 +1366,298 @@ smb_iod_shutdown_share(struct smb_share *ssp)
}
/*
- * Send all requests that need sending.
- * Called from _addrq, _multirq, _waitrq
+ * Ioctl functions called by the user-level I/O Deamon (IOD)
+ * to bring up and service a connection to some SMB server.
*/
-void
-smb_iod_sendall(smb_vc_t *vcp)
+
+/*
+ * Handle ioctl SMBIOC_IOD_CONNECT
+ */
+int
+nsmb_iod_connect(struct smb_vc *vcp, cred_t *cr)
{
- struct smb_rq *rqp;
- int error, muxcnt;
+ int err, val;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_connect: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
/*
- * Clear "newrq" to make sure threads adding
- * new requests will run this function again.
+ * Putting a TLI endpoint back in the right state for a new
+ * connection is a bit tricky. In theory, this could be:
+ * SMB_TRAN_DISCONNECT(vcp);
+ * SMB_TRAN_UNBIND(vcp);
+ * but that method often results in TOUTSTATE errors.
+ * It's easier to just close it and open a new endpoint.
*/
- rw_enter(&vcp->iod_rqlock, RW_WRITER);
- vcp->iod_newrq = 0;
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_tdata)
+ SMB_TRAN_DONE(vcp);
+ err = SMB_TRAN_CREATE(vcp, cr);
+ SMB_VC_UNLOCK(vcp);
+ if (err != 0)
+ return (err);
/*
- * We only read iod_rqlist, so downgrade rwlock.
- * This allows the IOD to handle responses while
- * some requesting thread may be blocked in send.
+ * Set various options on this endpoint.
+ * Keep going in spite of errors.
*/
- rw_downgrade(&vcp->iod_rqlock);
+ val = smb_tcpsndbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_SNDBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt SNDBUF, err=%d", err);
+ }
+ val = smb_tcprcvbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_RCVBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt RCVBUF, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_KEEPALIVE, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt KEEPALIVE, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_NODELAY, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP_NODELAY, err=%d", err);
+ }
+ val = smb_connect_timeout * 1000;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_CON_TMO, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP con tmo, err=%d", err);
+ }
/*
- * Serialize to prevent multiple senders.
- * Note lock order: iod_rqlock, vc_sendlock
+ * Bind and connect
*/
- sema_p(&vcp->vc_sendlock);
+ err = SMB_TRAN_BIND(vcp, NULL);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: t_kbind: err=%d", err);
+ /* Continue on and try connect. */
+ }
+ err = SMB_TRAN_CONNECT(vcp, &vcp->vc_srvaddr.sa);
+ /*
+ * No cmn_err here, as connect failures are normal, i.e.
+ * when a server has multiple addresses and only some are
+ * routed for us. (libsmbfs tries them all)
+ */
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_CONNECTED);
+ SMB_VC_UNLOCK(vcp);
+ } /* else stay in state reconnect */
+
+ return (err);
+}
+
+/*
+ * Handle ioctl SMBIOC_IOD_NEGOTIATE
+ * Do the whole SMB1/SMB2 negotiate
+ *
+ * This is where we send our first request to the server.
+ * If this is the first time we're talking to this server,
+ * (meaning not a reconnect) then we don't know whether
+ * the server supports SMB2, so we need to use the weird
+ * SMB1-to-SMB2 negotiation. That's where we send an SMB1
+ * negotiate including dialect "SMB 2.???" and if the
+ * server supports SMB2 we get an SMB2 reply -- Yes, an
+ * SMB2 reply to an SMB1 request. A strange protocol...
+ *
+ * If on the other hand we already know the server supports
+ * SMB2 (because this is a reconnect) or if the client side
+ * has disabled SMB1 entirely, we'll skip the SMB1 part.
+ */
+int
+nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
+{
+ struct smb_sopt *sv = &vcp->vc_sopt;
+ smb_cred_t scred;
+ int err = 0;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+
+ if (vcp->vc_state != SMBIOD_ST_CONNECTED) {
+ cmn_err(CE_NOTE, "iod_negotiate: bad state %d", vcp->vc_state);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (vcp->vc_maxver == 0 || vcp->vc_minver > vcp->vc_maxver) {
+ err = EINVAL;
+ goto out;
+ }
/*
- * Walk the list of requests and send when possible.
- * We avoid having more than vc_maxmux requests
- * outstanding to the server by traversing only
- * vc_maxmux entries into this list. Simple!
+ * (Re)init negotiated values
*/
- ASSERT(vcp->vc_maxmux > 0);
- error = muxcnt = 0;
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+ bzero(sv, sizeof (*sv));
+ vcp->vc2_next_message_id = 0;
+ vcp->vc2_limit_message_id = 1;
+ vcp->vc2_session_id = 0;
+ vcp->vc_next_seq = 0;
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- error = ENOTCONN; /* stop everything! */
- break;
- }
+ /*
+ * If this was reconnect, get rid of the old MAC key
+ * and session key.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_mackey != NULL) {
+ kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ vcp->vc_mackey = NULL;
+ vcp->vc_mackeylen = 0;
+ }
+ if (vcp->vc_ssnkey != NULL) {
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ vcp->vc_ssnkey = NULL;
+ vcp->vc_ssnkeylen = 0;
+ }
+ SMB_VC_UNLOCK(vcp);
- if (rqp->sr_state == SMBRQ_NOTSENT) {
- error = smb_iod_sendrq(rqp);
- if (error)
- break;
+ /*
+ * If this is not an SMB2 reconect (SMBV_SMB2 not set),
+ * and if SMB1 is enabled, do SMB1 neogotiate. Then
+ * if either SMB1-to-SMB2 negotiate tells us we should
+ * switch to SMB2, or the local configuration has
+ * disabled SMB1, set the SMBV_SMB2 flag.
+ *
+ * Note that vc_maxver is handled in smb_smb_negotiate
+ * so we never get sv_proto == SMB_DIALECT_SMB2_FF when
+ * the local configuration disables SMB2, and therefore
+ * we won't set the SMBV_SMB2 flag.
+ */
+ if ((vcp->vc_flags & SMBV_SMB2) == 0) {
+ if (vcp->vc_minver < SMB2_DIALECT_BASE) {
+ /*
+ * SMB1 is enabled
+ */
+ err = smb_smb_negotiate(vcp, &scred);
+ if (err != 0)
+ goto out;
}
-
- if (++muxcnt == vcp->vc_maxmux) {
- SMBIODEBUG("muxcnt == vc_maxmux\n");
- break;
+ /*
+ * If SMB1-to-SMB2 negotiate told us we should
+ * switch to SMB2, or if the local configuration
+ * disables SMB1, set the SMB2 flag.
+ */
+ if (sv->sv_proto == SMB_DIALECT_SMB2_FF ||
+ vcp->vc_minver >= SMB2_DIALECT_BASE) {
+ /*
+ * Switch this VC to SMB2.
+ */
+ SMB_VC_LOCK(vcp);
+ vcp->vc_flags |= SMBV_SMB2;
+ SMB_VC_UNLOCK(vcp);
}
+ }
+ /*
+ * If this is an SMB2 reconnect (SMBV_SMB2 was set before this
+ * function was called), or SMB1-to-SMB2 negotiate indicated
+ * we should switch to SMB2, or we have SMB1 disabled (both
+ * cases set SMBV_SMB2 above), then do SMB2 negotiate.
+ */
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ err = smb2_smb_negotiate(vcp, &scred);
}
+out:
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_NEGOTIATED);
+ SMB_VC_UNLOCK(vcp);
+ }
/*
- * If we have vc_maxmux requests outstanding,
- * arrange for _waitrq to call _sendall as
- * requests are completed.
+ * (else) leave state as it was.
+ * User-level will either close this handle (if connecting
+ * for the first time) or call rcfail and then try again.
*/
- vcp->iod_muxfull =
- (muxcnt < vcp->vc_maxmux) ? 0 : 1;
- sema_v(&vcp->vc_sendlock);
- rw_exit(&vcp->iod_rqlock);
+ smb_credrele(&scred);
+
+ return (err);
}
+/*
+ * Handle ioctl SMBIOC_IOD_SSNSETUP
+ * Do either SMB1 or SMB2 session setup (one call/reply)
+ */
int
-smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
+nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
{
- struct file *fp = NULL;
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ switch (vcp->vc_state) {
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ smb_credinit(&scred, cr);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_smb_ssnsetup(vcp, &scred);
+ else
+ err = smb_smb_ssnsetup(vcp, &scred);
+ smb_credrele(&scred);
+
+ SMB_VC_LOCK(vcp);
+ switch (err) {
+ case 0:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHOK);
+ break;
+ case EINPROGRESS: /* MORE_PROCESSING_REQUIRED */
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHCONT);
+ break;
+ default:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHFAIL);
+ break;
+ }
+ SMB_VC_UNLOCK(vcp);
+
+ return (err);
+}
+
+static int
+smb_iod_logoff(struct smb_vc *vcp, cred_t *cr)
+{
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_smb_logoff(vcp, &scred);
+ else
+ err = smb_smb_logoff(vcp, &scred);
+ smb_credrele(&scred);
+
+ return (err);
+}
+
+/*
+ * Handle ioctl SMBIOC_IOD_WORK
+ *
+ * The smbiod agent calls this after authentication to become
+ * the reader for this session, so long as that's possible.
+ * This should only return non-zero if we want that agent to
+ * give up on this VC permanently.
+ */
+/* ARGSUSED */
+int
+smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
+{
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
int err = 0;
/*
@@ -967,19 +1667,57 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
ASSERT(vcp->iod_thr == curthread);
/*
- * Get the network transport file pointer,
- * and "loan" it to our transport module.
+ * Should be in state...
*/
- if ((fp = getf(vcp->vc_tran_fd)) == NULL) {
- err = EBADF;
- goto out;
+ if (vcp->vc_state != SMBIOD_ST_AUTHOK) {
+ cmn_err(CE_NOTE, "iod_vc_work: bad state %d", vcp->vc_state);
+ return (EINVAL);
}
- if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0)
- goto out;
/*
- * In case of reconnect, tell any enqueued requests
- * then can GO!
+ * Update the session key and initialize SMB signing.
+ *
+ * This implementation does not use multiple SMB sessions per
+ * TCP connection (where only the first session key is used)
+ * so we always have a new session key here. Sanity check the
+ * length from user space. Normally 16 or 32.
+ */
+ if (wk->wk_u_ssnkey_len > 1024) {
+ cmn_err(CE_NOTE, "iod_vc_work: ssn key too long");
+ return (EINVAL);
+ }
+
+ ASSERT(vcp->vc_ssnkey == NULL);
+ SMB_VC_LOCK(vcp);
+ if (wk->wk_u_ssnkey_len != 0 &&
+ wk->wk_u_ssnkey_buf.lp_ptr != NULL) {
+ vcp->vc_ssnkeylen = wk->wk_u_ssnkey_len;
+ vcp->vc_ssnkey = kmem_alloc(vcp->vc_ssnkeylen, KM_SLEEP);
+ if (ddi_copyin(wk->wk_u_ssnkey_buf.lp_ptr,
+ vcp->vc_ssnkey, vcp->vc_ssnkeylen, flags) != 0) {
+ err = EFAULT;
+ }
+ }
+ SMB_VC_UNLOCK(vcp);
+ if (err)
+ return (err);
+
+ /*
+ * If we have a session key, derive the MAC key for SMB signing.
+ * If this was a NULL session, we might have no session key.
+ */
+ ASSERT(vcp->vc_mackey == NULL);
+ if (vcp->vc_ssnkey != NULL) {
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_sign_init(vcp);
+ else
+ err = smb_sign_init(vcp);
+ if (err != 0)
+ return (err);
+ }
+
+ /*
+ * Tell any enqueued requests they can start.
*/
SMB_VC_LOCK(vcp);
vcp->vc_genid++; /* possibly new connection */
@@ -998,9 +1736,11 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
smb_vc_walkshares(vcp, fscb->fscb_connect);
/*
- * Run the "reader" loop.
+ * Run the "reader" loop. An error return here is normal
+ * (i.e. when we need to reconnect) so ignore errors.
+ * Note: This call updates the vc_state.
*/
- err = smb_iod_recvall(vcp);
+ (void) smb_iod_recvall(vcp, B_FALSE);
/*
* The reader loop returned, so we must have a
@@ -1021,26 +1761,24 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
*/
smb_iod_invrq(vcp);
-out:
- /* Recall the file descriptor loan. */
- (void) SMB_TRAN_LOAN_FP(vcp, NULL, cr);
- if (fp != NULL) {
- releasef(vcp->vc_tran_fd);
- }
-
return (err);
}
/*
- * Wait around for someone to ask to use this VC.
- * If the VC has only the IOD reference, then
- * wait only a minute or so, then drop it.
+ * Handle ioctl SMBIOC_IOD_IDLE
+ *
+ * Wait around for someone to ask to use this VC again after the
+ * TCP session has closed. When one of the connected trees adds a
+ * request, smb_iod_reconnect will set vc_state to RECONNECT and
+ * wake this cv_wait. When a VC ref. goes away in smb_vc_rele,
+ * that also signals this wait so we can re-check whether we
+ * now hold the last ref. on this VC (and can destroy it).
*/
int
smb_iod_vc_idle(struct smb_vc *vcp)
{
- clock_t tr, delta = SEC_TO_TICK(15);
int err = 0;
+ boolean_t destroy = B_FALSE;
/*
* This is called by the one-and-only
@@ -1048,30 +1786,50 @@ smb_iod_vc_idle(struct smb_vc *vcp)
*/
ASSERT(vcp->iod_thr == curthread);
+ /*
+ * Should be in state...
+ */
+ if (vcp->vc_state != SMBIOD_ST_IDLE &&
+ vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_vc_idle: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
+
SMB_VC_LOCK(vcp);
- while (vcp->vc_state == SMBIOD_ST_IDLE) {
- tr = cv_reltimedwait_sig(&vcp->iod_idle, &vcp->vc_lock,
- delta, TR_CLOCK_TICK);
- if (tr == 0) {
+
+ while (vcp->vc_state == SMBIOD_ST_IDLE &&
+ vcp->vc_co.co_usecount > 1) {
+ if (cv_wait_sig(&vcp->iod_idle, &vcp->vc_lock) == 0) {
err = EINTR;
break;
}
- if (tr < 0) {
- /* timeout */
- if (vcp->vc_co.co_usecount == 1) {
- /* Let this IOD terminate. */
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
- /* nobody to cv_broadcast */
- break;
- }
- }
}
+ if (vcp->vc_state == SMBIOD_ST_IDLE &&
+ vcp->vc_co.co_usecount == 1) {
+ /*
+ * We were woken because we now have the last ref.
+ * Arrange for this VC to be destroyed now.
+ * Set the "GONE" flag while holding the lock,
+ * to prevent a race with new references.
+ * The destroy happens after unlock.
+ */
+ vcp->vc_flags |= SMBV_GONE;
+ destroy = B_TRUE;
+ }
+
SMB_VC_UNLOCK(vcp);
+ if (destroy) {
+ /* This sets vc_state = DEAD */
+ smb_iod_disconnect(vcp);
+ }
+
return (err);
}
/*
+ * Handle ioctl SMBIOC_IOD_RCFAIL
+ *
* After a failed reconnect attempt, smbiod will
* call this to make current requests error out.
*/
@@ -1086,10 +1844,6 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
* IOD thread for this VC.
*/
ASSERT(vcp->iod_thr == curthread);
-
- if (vcp->vc_state != SMBIOD_ST_RECONNECT)
- return (EINVAL);
-
SMB_VC_LOCK(vcp);
smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED);
@@ -1105,8 +1859,18 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
if (tr == 0)
err = EINTR;
- smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
- cv_broadcast(&vcp->vc_statechg);
+ /*
+ * Normally we'll switch to state IDLE here. However,
+ * if something called smb_iod_reconnect() while we were
+ * waiting above, we'll be in in state reconnect already.
+ * In that case, keep state RECONNECT, so we essentially
+ * skip transition through state IDLE that would normally
+ * happen next.
+ */
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
+ cv_broadcast(&vcp->vc_statechg);
+ }
SMB_VC_UNLOCK(vcp);
@@ -1127,11 +1891,17 @@ again:
switch (vcp->vc_state) {
case SMBIOD_ST_IDLE:
+ /* Tell the IOD thread it's no longer IDLE. */
smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
cv_signal(&vcp->iod_idle);
/* FALLTHROUGH */
case SMBIOD_ST_RECONNECT:
+ case SMBIOD_ST_CONNECTED:
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ case SMBIOD_ST_AUTHOK:
+ /* Wait for the VC state to become ACTIVE. */
rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock);
if (rv == 0) {
err = EINTR;
@@ -1143,6 +1913,7 @@ again:
err = 0; /* success! */
break;
+ case SMBIOD_ST_AUTHFAIL:
case SMBIOD_ST_RCFAILED:
case SMBIOD_ST_DEAD:
default:
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
index 712acb6f3b..aef9e70e27 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
@@ -1,16 +1,35 @@
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2001 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
/*
* Code corresponding to smb_apple.h
- * XXX: Could merge this into smb_subr.h
- * as long as that doesn't break smbfs
*/
#ifndef _NETSMB_SMB_OSDEP_H_
#define _NETSMB_SMB_OSDEP_H_
#ifndef PRIVSYM
-#define PRIVSYM
+#define PRIVSYM
#endif
#ifndef min
@@ -65,8 +84,14 @@ typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
-typedef const char * c_caddr_t;
-typedef uint64_t user_addr_t;
+typedef const char *c_caddr_t;
+typedef uint64_t user_addr_t;
+typedef ssize_t user_ssize_t;
+typedef size_t user_size_t;
+
+#ifdef _FAKE_KERNEL
+#define ddi_get_cred() CRED()
+#endif
/*
* Time related calls.
@@ -75,7 +100,7 @@ typedef uint64_t user_addr_t;
/* BEGIN CSTYLED */
#define timespeccmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
- ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
+ ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
/* END CSTYLED */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
index f4ebf9a573..4a44e36e89 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_PASS_H
@@ -44,14 +46,13 @@ typedef struct smb_passid {
zoneid_t zoneid; /* Future Use */
char *srvdom; /* Windows Domain (or server) */
char *username; /* Windows User name */
- uchar_t lmhash[SMBIOC_HASH_SZ];
- uchar_t nthash[SMBIOC_HASH_SZ];
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
} smb_passid_t;
/* Called from smb_dev.c */
void smb_pkey_init(void);
void smb_pkey_fini(void);
int smb_pkey_idle(void);
-int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
#endif /* _SMB_PASS_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
index 997b7318dd..1c62850599 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
@@ -34,6 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -51,10 +53,12 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
/*
* How long to wait before restarting a request (after reconnect)
@@ -69,9 +73,8 @@
static int smb_rq_reply(struct smb_rq *rqp);
+static int smb_rq_parsehdr(struct smb_rq *rqp);
static int smb_rq_enqueue(struct smb_rq *rqp);
-static int smb_rq_getenv(struct smb_connobj *layer,
- struct smb_vc **vcpp, struct smb_share **sspp);
static int smb_rq_new(struct smb_rq *rqp, uchar_t cmd);
static int smb_t2_reply(struct smb_t2rq *t2p);
static int smb_nt_reply(struct smb_ntrq *ntp);
@@ -147,7 +150,6 @@ smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd,
rqp->sr_rexmit = SMBMAXRESTARTS;
rqp->sr_cred = scred; /* Note: ref hold done by caller. */
- rqp->sr_pid = (uint16_t)ddi_get_pid();
error = smb_rq_new(rqp, cmd);
return (error);
@@ -163,7 +165,6 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
ASSERT(rqp != NULL);
rqp->sr_sendcnt = 0;
- rqp->sr_cmd = cmd;
mb_done(mbp);
md_done(&rqp->sr_rp);
@@ -171,18 +172,42 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
if (error)
return (error);
- /*
- * Is this the right place to save the flags?
- */
- rqp->sr_rqflags = vcp->vc_hflags;
- rqp->sr_rqflags2 = vcp->vc_hflags2;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ /*
+ * SMB2 request initialization
+ */
+ rqp->sr2_command = cmd;
+ rqp->sr2_creditcharge = 1;
+ rqp->sr2_creditsrequested = 1;
+ rqp->sr_pid = 0xFEFF; /* Made up, just like Windows */
+ rqp->sr2_rqflags = 0;
+ if ((vcp->vc_flags & SMBV_SIGNING) != 0 &&
+ vcp->vc_mackey != NULL) {
+ rqp->sr2_rqflags |= SMB2_FLAGS_SIGNED;
+ }
- /*
- * The SMB header is filled in later by
- * smb_rq_fillhdr (see below)
- * Just reserve space here.
- */
- mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+ /*
+ * The SMB2 header is filled in later by
+ * smb2_rq_fillhdr (see smb2_rq.c)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB2_HDRLEN, MB_MZERO);
+ } else {
+ /*
+ * SMB1 request initialization
+ */
+ rqp->sr_cmd = cmd;
+ rqp->sr_pid = (uint32_t)ddi_get_pid();
+ rqp->sr_rqflags = vcp->vc_hflags;
+ rqp->sr_rqflags2 = vcp->vc_hflags2;
+
+ /*
+ * The SMB header is filled in later by
+ * smb_rq_fillhdr (see below)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+ }
return (0);
}
@@ -190,7 +215,7 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
/*
* Given a request with it's body already composed,
* rewind to the start and fill in the SMB header.
- * This is called after the request is enqueued,
+ * This is called when the request is enqueued,
* so we have the final MID, seq num. etc.
*/
void
@@ -217,7 +242,7 @@ smb_rq_fillhdr(struct smb_rq *rqp)
mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */
mb_put_uint16le(mbp, 0); /* reserved */
mb_put_uint16le(mbp, rqp->sr_rqtid);
- mb_put_uint16le(mbp, rqp->sr_pid);
+ mb_put_uint16le(mbp, (uint16_t)rqp->sr_pid);
mb_put_uint16le(mbp, rqp->sr_rquid);
mb_put_uint16le(mbp, rqp->sr_mid);
@@ -281,6 +306,8 @@ smb_rq_enqueue(struct smb_rq *rqp)
struct smb_share *ssp = rqp->sr_share;
int error = 0;
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+
/*
* Normal requests may initiate a reconnect,
* and/or wait for state changes to finish.
@@ -325,7 +352,71 @@ smb_rq_enqueue(struct smb_rq *rqp)
ok_out:
rqp->sr_rquid = vcp->vc_smbuid;
rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN;
- error = smb_iod_addrq(rqp);
+ error = smb1_iod_addrq(rqp);
+
+ return (error);
+}
+
+/*
+ * Used by the IOD thread during connection setup,
+ * and for smb_echo after network timeouts. Note that
+ * unlike smb_rq_simple, callers must check sr_error.
+ */
+int
+smb_rq_internal(struct smb_rq *rqp, int timeout)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int error;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ /*
+ * In-line smb_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. for an internal request.
+ */
+ rqp->sr_rquid = vcp->vc_smbuid;
+ rqp->sr_rqtid = SMB_TID_UNKNOWN;
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb1_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * In-line a variant of smb_rq_reply(rqp) here as we may
+ * need to do custom parsing for SMB1-to-SMB2 negotiate.
+ */
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq_int(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ error = smb_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB header.
+ */
+ error = smb_rq_parsehdr(rqp);
+
+ /*
+ * Skip the error translation smb_rq_reply does.
+ * Callers of this expect "raw" NT status.
+ */
return (error);
}
@@ -398,15 +489,6 @@ smb_rq_bend(struct smb_rq *rqp)
}
int
-smb_rq_intr(struct smb_rq *rqp)
-{
- if (rqp->sr_flags & SMBR_INTR)
- return (EINTR);
-
- return (0);
-}
-
-static int
smb_rq_getenv(struct smb_connobj *co,
struct smb_vc **vcpp, struct smb_share **sspp)
{
@@ -457,14 +539,12 @@ out:
}
/*
- * Wait for reply on the request
+ * Wait for a reply to this request, then parse it.
*/
static int
smb_rq_reply(struct smb_rq *rqp)
{
- struct mdchain *mdp = &rqp->sr_rp;
- u_int8_t tb;
- int error, rperror = 0;
+ int error;
if (rqp->sr_timo == SMBNOREPLYWAIT) {
smb_iod_removerq(rqp);
@@ -488,14 +568,23 @@ smb_rq_reply(struct smb_rq *rqp)
/*
* Parse the SMB header
*/
- error = md_get_uint32le(mdp, NULL);
- if (error)
+ error = smb_rq_parsehdr(rqp);
+ if (error != 0)
return (error);
- error = md_get_uint8(mdp, &tb);
- error = md_get_uint32le(mdp, &rqp->sr_error);
- error = md_get_uint8(mdp, &rqp->sr_rpflags);
- error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
- if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+
+ if (rqp->sr_error != 0) {
+ if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+ error = smb_maperr32(rqp->sr_error);
+ } else {
+ uint8_t errClass = rqp->sr_error & 0xff;
+ uint16_t errCode = rqp->sr_error >> 16;
+ /* Convert to NT status */
+ rqp->sr_error = smb_doserr2status(errClass, errCode);
+ error = smb_maperror(errClass, errCode);
+ }
+ }
+
+ if (error != 0) {
/*
* Do a special check for STATUS_BUFFER_OVERFLOW;
* it's not an error.
@@ -506,34 +595,65 @@ smb_rq_reply(struct smb_rq *rqp)
* they can look at rqp->sr_error if they
* need to know whether we got a
* STATUS_BUFFER_OVERFLOW.
- * XXX - should we do that for all errors
- * where (error & 0xC0000000) is 0x80000000,
- * i.e. all warnings?
*/
- rperror = 0;
- } else
- rperror = smb_maperr32(rqp->sr_error);
+ rqp->sr_flags |= SMBR_MOREDATA;
+ error = 0;
+ }
} else {
- rqp->sr_errclass = rqp->sr_error & 0xff;
- rqp->sr_serror = rqp->sr_error >> 16;
- rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
- }
- if (rperror == EMOREDATA) {
- rperror = E2BIG;
- rqp->sr_flags |= SMBR_MOREDATA;
- } else
rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
+
+ return (error);
+}
+
+/*
+ * Parse the SMB header
+ */
+static int
+smb_rq_parsehdr(struct smb_rq *rqp)
+{
+ struct mdchain mdp_save;
+ struct mdchain *mdp = &rqp->sr_rp;
+ u_int8_t tb, sig[4];
+ int error;
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
+ /*
+ * Parse the signature. The reader already checked that
+ * the signature is valid. Here we just have to check
+ * for SMB1-to-SMB2 negotiate. Caller handles an EPROTO
+ * as a signal that we got an SMB2 reply. If we return
+ * EPROTO, rewind the mdchain back where it was.
+ */
+ mdp_save = *mdp;
+ error = md_get_mem(mdp, sig, 4, MB_MSYSTEM);
+ if (error)
+ return (error);
+ if (sig[0] != SMB_HDR_V1) {
+ if (rqp->sr_cmd == SMB_COM_NEGOTIATE) {
+ *mdp = mdp_save;
+ return (EPROTO);
+ }
+ return (EBADRPC);
+ }
+
+ /* Check cmd */
+ error = md_get_uint8(mdp, &tb);
+ if (tb != rqp->sr_cmd)
+ return (EBADRPC);
+
+ md_get_uint32le(mdp, &rqp->sr_error);
+ md_get_uint8(mdp, &rqp->sr_rpflags);
+ md_get_uint16le(mdp, &rqp->sr_rpflags2);
- error = md_get_uint16le(mdp, &rqp->sr_rptid);
- error = md_get_uint16le(mdp, &rqp->sr_rppid);
- error = md_get_uint16le(mdp, &rqp->sr_rpuid);
+ /* Skip: pid-high(2), MAC sig(8), reserved(2) */
+ md_get_mem(mdp, NULL, 12, MB_MSYSTEM);
+
+ md_get_uint16le(mdp, &rqp->sr_rptid);
+ md_get_uint16le(mdp, &rqp->sr_rppid);
+ md_get_uint16le(mdp, &rqp->sr_rpuid);
error = md_get_uint16le(mdp, &rqp->sr_rpmid);
- return ((error) ? error : rperror);
+ return (error);
}
@@ -1134,7 +1254,7 @@ smb_t2_request_int(struct smb_t2rq *t2p)
mb_put_mbuf(mbp, m);
}
smb_rq_bend(rqp);
- error = smb_iod_multirq(rqp);
+ error = smb1_iod_multirq(rqp);
if (error)
goto bad;
} /* while left params or data */
@@ -1345,7 +1465,7 @@ smb_nt_request_int(struct smb_ntrq *ntp)
mb_put_mbuf(mbp, m);
}
smb_rq_bend(rqp);
- error = smb_iod_multirq(rqp);
+ error = smb1_iod_multirq(rqp);
if (error)
goto bad;
} /* while left params or data */
@@ -1438,3 +1558,83 @@ smb_nt_request(struct smb_ntrq *ntp)
}
return (error);
}
+
+/*
+ * Run an SMB transact named pipe.
+ * Note: send_mb is consumed.
+ */
+int
+smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *send_mb, struct mdchain *recv_md,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t *more, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p = NULL;
+ mblk_t *m;
+ uint16_t setup[2];
+ int err;
+
+ setup[0] = TRANS_TRANSACT_NAMED_PIPE;
+ setup[1] = fid;
+
+ t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
+ err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, scrp);
+ if (err) {
+ *data_out_sz = 0;
+ goto out;
+ }
+
+ t2p->t2_setupcount = 2;
+ t2p->t2_setupdata = setup;
+
+ t2p->t_name = "\\PIPE\\";
+ t2p->t_name_len = 6;
+
+ t2p->t2_maxscount = 0;
+ t2p->t2_maxpcount = 0;
+ t2p->t2_maxdcount = (uint16_t)*data_out_sz;
+
+ /* Transmit parameters (none) */
+
+ /*
+ * Transmit data
+ *
+ * Copy the mb, and clear the source so we
+ * don't end up with a double free.
+ */
+ t2p->t2_tdata = *send_mb;
+ bzero(send_mb, sizeof (*send_mb));
+
+ /*
+ * Run the request
+ */
+ err = smb_t2_request(t2p);
+
+ /* No returned parameters. */
+
+ if (err == 0 && (m = t2p->t2_rdata.md_top) != NULL) {
+ /*
+ * Received data
+ *
+ * Copy the mdchain, and clear the source so we
+ * don't end up with a double free.
+ */
+ *data_out_sz = msgdsize(m);
+ md_initm(recv_md, m);
+ t2p->t2_rdata.md_top = NULL;
+ } else {
+ *data_out_sz = 0;
+ }
+
+ if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
+ *more = 1;
+
+out:
+ if (t2p != NULL) {
+ /* Note: t2p->t_name no longer allocated */
+ smb_t2_done(t2p);
+ kmem_free(t2p, sizeof (*t2p));
+ }
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
index 0184022a65..7c3106612c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
@@ -34,6 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_RQ_H_
@@ -54,8 +56,12 @@
#define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */
#define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */
#define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */
-/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
+/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
#define SMBR_MOREDATA 0x8000 /* our buffer was too small */
+#define SMBR_COMPOUND_RQ 0x10000 /* SMB 2/3 compound request */
+#define SMBR_ASYNC 0x20000 /* got async response */
+#define SMBR_RECONNECTED 0x40000 /* reconnected during request */
+
#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */
#define SMBT2_ALLRECV 0x0002 /* all data and params are received */
@@ -64,7 +70,7 @@
#define SMBT2_NORESTART 0x0010
#define SMBT2_MOREDATA 0x8000 /* our buffer was too small */
-#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
+#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
#define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock)
enum smbrq_state {
@@ -83,7 +89,7 @@ struct smb_rq {
enum smbrq_state sr_state;
struct smb_vc *sr_vc;
struct smb_share *sr_share;
- struct _kthread *sr_owner;
+ struct _kthread *sr_owner;
uint32_t sr_seqno; /* Seq. no. of request */
uint32_t sr_rseqno; /* Seq. no. of reply */
struct mbchain sr_rq;
@@ -91,11 +97,24 @@ struct smb_rq {
uint8_t sr_rqflags;
uint16_t sr_rqflags2;
uint16_t sr_rqtid;
- uint16_t sr_pid;
+ uint32_t sr_pid;
uint16_t sr_rquid;
uint16_t sr_mid;
uchar_t *sr_wcount;
uchar_t *sr_bcount;
+
+ /* SMB 2/3 request fields */
+ struct smb_rq *sr2_compound_next;
+ uint16_t sr2_command;
+ uint16_t sr2_totalcreditcharge;
+ uint16_t sr2_creditcharge;
+ uint16_t sr2_creditsrequested;
+ uint32_t sr2_rqflags;
+ uint32_t sr2_nextcmd;
+ uint64_t sr2_messageid; /* local copy of message id */
+ uint64_t sr2_rqsessionid;
+ uint32_t sr2_rqtreeid;
+
struct mdchain sr_rp;
int sr_rpgen;
int sr_rplast;
@@ -105,7 +124,7 @@ struct smb_rq {
int sr_timo;
int sr_rexmit; /* how many more retries. dflt 0 */
int sr_sendcnt;
- struct timespec sr_timesent;
+ struct timespec sr_timesent;
int sr_lerror;
uint8_t sr_errclass;
uint16_t sr_serror;
@@ -116,6 +135,15 @@ struct smb_rq {
uint16_t sr_rppid;
uint16_t sr_rpuid;
uint16_t sr_rpmid;
+
+ /* SMB2 response fields */
+ uint16_t sr2_rspcreditsgranted;
+ uint32_t sr2_rspflags;
+ uint32_t sr2_rspnextcmd;
+ uint32_t sr2_rsppid;
+ uint32_t sr2_rsptreeid;
+ uint64_t sr2_rspasyncid;
+ uint64_t sr2_rspsessionid;
};
typedef struct smb_rq smb_rq_t;
@@ -124,7 +152,7 @@ struct smb_t2rq {
kcondvar_t t2_cond;
uint16_t t2_setupcount;
uint16_t *t2_setupdata;
- uint16_t t2_setup[SMBIOC_T2RQ_MAXSETUP];
+ uint16_t t2_setup[4];
uint8_t t2_maxscount; /* max setup words to return */
uint16_t t2_maxpcount; /* max param bytes to return */
uint16_t t2_maxdcount; /* max data bytes to return */
@@ -184,15 +212,19 @@ int smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd,
struct smb_cred *scred, struct smb_rq **rqpp);
int smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer,
uchar_t cmd, struct smb_cred *scred);
+int smb_rq_getenv(struct smb_connobj *layer,
+ struct smb_vc **vcpp, struct smb_share **sspp);
void smb_rq_fillhdr(struct smb_rq *rqp);
void smb_rq_wstart(struct smb_rq *rqp);
void smb_rq_wend(struct smb_rq *rqp);
void smb_rq_bstart(struct smb_rq *rqp);
void smb_rq_bend(struct smb_rq *rqp);
-int smb_rq_intr(struct smb_rq *rqp);
int smb_rq_simple(struct smb_rq *rqp);
int smb_rq_simple_timed(struct smb_rq *rqp, int timeout);
+int smb_rq_internal(struct smb_rq *rqp, int timeout);
+
+int smb2_parse_smb1nego_resp(struct smb_rq *rqp);
int smb_t2_alloc(struct smb_connobj *layer, ushort_t setup,
struct smb_cred *scred, struct smb_t2rq **rqpp);
@@ -201,6 +233,10 @@ int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer,
void smb_t2_done(struct smb_t2rq *t2p);
int smb_t2_request(struct smb_t2rq *t2p);
+int smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *send_mb, struct mdchain *recv_md,
+ uint32_t *data_out_sz, uint32_t *more, struct smb_cred *scrp);
+
int smb_nt_alloc(struct smb_connobj *layer, ushort_t fn,
struct smb_cred *scred, struct smb_ntrq **rqpp);
int smb_nt_init(struct smb_ntrq *rqp, struct smb_connobj *layer,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
index cf06e75767..bec61e4392 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -37,8 +38,6 @@
#include <sys/md5.h>
#include <sys/des.h>
#include <sys/kmem.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/common.h>
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <sys/strsun.h>
@@ -50,6 +49,7 @@
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
#ifdef DEBUG
/*
@@ -59,15 +59,37 @@
int nsmb_signing_fudge = 0;
#endif
-/* Mechanism definitions */
-static crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
-
-void
-smb_crypto_mech_init(void)
+/*
+ * This is called just after session setup completes,
+ * at the top of smb_iod_vc_work(). Initialize signing.
+ */
+int
+smb_sign_init(smb_vc_t *vcp)
{
- crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
-}
+ int rc;
+ ASSERT(vcp->vc_ssnkey != NULL);
+ ASSERT(vcp->vc_mackey == NULL);
+
+ rc = smb_md5_getmech(&vcp->vc_signmech);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb can't get signing mechanism");
+ return (EAUTH);
+ }
+
+ /*
+ * Convert the session key to the MAC key.
+ * SMB1 uses the whole session key.
+ */
+ vcp->vc_mackeylen = vcp->vc_ssnkeylen;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
+
+ /* The initial sequence number is two. */
+ vcp->vc_next_seq = 2;
+
+ return (0);
+}
#define SMBSIGLEN 8 /* SMB signature length */
@@ -83,12 +105,12 @@ static int
smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
uint32_t seqno, uchar_t *signature)
{
- crypto_context_t crypto_ctx;
- crypto_data_t key;
- crypto_data_t data;
- crypto_data_t digest;
- uchar_t mac[16];
- int status;
+ uchar_t digest[MD5_DIGEST_LENGTH];
+ smb_sign_ctx_t ctx = 0;
+ mblk_t *m = mp;
+ int size;
+ int rc;
+
/*
* This union is a little bit of trickery to:
* (1) get the sequence number int aligned, and
@@ -109,78 +131,64 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
} s;
} smbhdr;
- ASSERT(mp != NULL);
- ASSERT(MBLKL(mp) >= SMB_HDRLEN);
- ASSERT(vcp->vc_mackey != NULL);
+ if (vcp->vc_mackey == NULL)
+ return (-1);
+
+ if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
+ return (rc);
+
+ /* Digest the MAC Key */
+ rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
+ if (rc != 0)
+ return (rc);
+
+ /* Our caller should ensure mp has a contiguous header */
+ ASSERT(m != NULL);
+ ASSERT(MBLKL(m) >= SMB_HDRLEN);
/*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
+ * Make an aligned copy of the SMB header,
+ * fill in the sequence number, and digest.
*/
- bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
+ size = SMB_HDRLEN;
+ bcopy(m->b_rptr, smbhdr.r.raw, size);
smbhdr.s.sig[0] = htolel(seqno);
smbhdr.s.sig[1] = 0;
+ rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
+ if (rc != 0)
+ return (rc);
+
/*
- * Compute the MAC: MD5(concat(Key, message))
+ * Digest the rest of the SMB header packet, starting at
+ * the data just after the SMB header.
*/
- if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
- SMBSDEBUG("crypto_mech_md5 invalid\n");
- return (CRYPTO_MECHANISM_INVALID);
- }
- status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the MAC Key */
- key.cd_format = CRYPTO_DATA_RAW;
- key.cd_offset = 0;
- key.cd_length = vcp->vc_mackeylen;
- key.cd_miscdata = 0;
- key.cd_raw.iov_base = (char *)vcp->vc_mackey;
- key.cd_raw.iov_len = vcp->vc_mackeylen;
- status = crypto_digest_update(crypto_ctx, &key, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the (copied) SMB header */
- data.cd_format = CRYPTO_DATA_RAW;
- data.cd_offset = 0;
- data.cd_length = SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_raw.iov_base = (char *)smbhdr.r.raw;
- data.cd_raw.iov_len = SMB_HDRLEN;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
+ size = MBLKL(m) - SMB_HDRLEN;
+ rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
+ if (rc != 0)
+ return (rc);
+ m = m->b_cont;
/* Digest rest of the SMB message. */
- data.cd_format = CRYPTO_DATA_MBLK;
- data.cd_offset = SMB_HDRLEN;
- data.cd_length = msgdsize(mp) - SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_mp = mp;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Final */
- digest.cd_format = CRYPTO_DATA_RAW;
- digest.cd_offset = 0;
- digest.cd_length = sizeof (mac);
- digest.cd_miscdata = 0;
- digest.cd_raw.iov_base = (char *)mac;
- digest.cd_raw.iov_len = sizeof (mac);
- status = crypto_digest_final(crypto_ctx, &digest, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
+ while (m != NULL) {
+ size = MBLKL(m);
+ if (size > 0) {
+ rc = smb_md5_update(ctx, m->b_rptr, size);
+ if (rc != 0)
+ return (rc);
+ }
+ m = m->b_cont;
+ }
+ rc = smb_md5_final(ctx, digest);
+ if (rc != 0)
+ return (rc);
/*
* Finally, store the signature.
* (first 8 bytes of the mac)
*/
- if (signature)
- bcopy(mac, signature, SMBSIGLEN);
+ if (signature != NULL)
+ bcopy(digest, signature, SMBSIGLEN);
return (0);
}
@@ -197,13 +205,10 @@ smb_rq_sign(struct smb_rq *rqp)
int status;
/*
- * Our mblk allocation ensures this,
- * but just in case...
+ * smb_rq_new() ensures this,
+ * but just in case..
*/
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return;
- }
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
sigloc = mp->b_rptr + SMBSIGOFF;
if (vcp->vc_mackey == NULL) {
@@ -221,7 +226,7 @@ smb_rq_sign(struct smb_rq *rqp)
* directly into the message at sigloc.
*/
status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
- if (status != CRYPTO_SUCCESS) {
+ if (status != 0) {
SMBSDEBUG("Crypto error %d", status);
bzero(sigloc, SMBSIGLEN);
}
@@ -256,10 +261,8 @@ smb_rq_verify(struct smb_rq *rqp)
SMBSDEBUG("empty reply\n");
return (0);
}
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return (0);
- }
+
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
sigloc = mp->b_rptr + SMBSIGOFF;
/*
@@ -267,7 +270,7 @@ smb_rq_verify(struct smb_rq *rqp)
*/
rsn = rqp->sr_rseqno;
status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
- if (status != CRYPTO_SUCCESS) {
+ if (status != 0) {
SMBSDEBUG("Crypto error %d", status);
/*
* If we can't compute a MAC, then there's
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
new file mode 100644
index 0000000000..e1799e3383
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SMB_SIGNING_H_
+#define _SMB_SIGNING_H_
+
+/*
+ * SMB signing routines used in {smb,smb2}_sign.c
+ * Two implementations of these (kernel/user) in:
+ * uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
+ * lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+ */
+
+#ifdef _KERNEL
+#include <sys/crypto/api.h>
+#else
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */
+#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
+#define SMB2_SIG_SIZE 16
+
+#ifdef _KERNEL
+/* KCF variant */
+typedef crypto_mechanism_t smb_sign_mech_t;
+typedef crypto_context_t smb_sign_ctx_t;
+#else /* _KERNEL */
+/* PKCS11 variant */
+typedef CK_MECHANISM smb_sign_mech_t;
+typedef CK_SESSION_HANDLE smb_sign_ctx_t;
+#endif /* _KERNEL */
+
+/*
+ * SMB signing routines used in smb_signing.c
+ */
+
+int smb_md5_getmech(smb_sign_mech_t *);
+int smb_md5_init(smb_sign_ctx_t *, smb_sign_mech_t *);
+int smb_md5_update(smb_sign_ctx_t, void *, size_t);
+int smb_md5_final(smb_sign_ctx_t, uint8_t *);
+
+/*
+ * SMB2 signing routines used in smb2_signing.c
+ */
+
+int smb2_hmac_getmech(smb_sign_mech_t *);
+int smb2_hmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t);
+int smb2_hmac_update(smb_sign_ctx_t, uint8_t *, size_t);
+int smb2_hmac_final(smb_sign_ctx_t, uint8_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_SIGNING_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
index 6016f5061a..566f131316 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
@@ -33,8 +33,9 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -49,6 +50,7 @@
#include <sys/uio.h>
#include <sys/random.h>
#include <sys/note.h>
+#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
@@ -61,14 +63,25 @@
#define STYPE_LEN 8 /* share type strings */
-/*
- * Largest size to use with LARGE_READ/LARGE_WRITE.
- * Specs say up to 64k data bytes, but Windows traffic
- * uses 60k... no doubt for some good reason.
- * (Probably to keep 4k block alignment.)
- * XXX: Move to smb.h maybe?
- */
-#define SMB_MAX_LARGE_RW_SIZE (60*1024)
+struct smb_dialect {
+ int d_id;
+ const char *d_name;
+};
+
+static struct smb_dialect smb_dialects[3] = {
+ {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
+ {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
+#define NDIALECT_SMB1 2
+ {SMB_DIALECT_SMB2_FF, "SMB 2.???"},
+#define NDIALECT_SMB2 3
+};
+
+static const uint32_t smb_clnt_caps_mask =
+ SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_NT_SMBS |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_EXT_SECURITY;
/*
* Default timeout values, all in seconds.
@@ -76,20 +89,526 @@
*/
int smb_timo_notice = 15;
int smb_timo_default = 30; /* was SMB_DEFRQTIMO */
+int smb_timo_logon = 45;
int smb_timo_open = 45;
int smb_timo_read = 45;
int smb_timo_write = 60; /* was SMBWRTTIMO */
int smb_timo_append = 90;
-static int smb_smb_read(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-static int smb_smb_write(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
+int
+smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ struct smb_dialect *dp;
+ int err, sblen, tlen;
+ uint8_t wc, eklen;
+ uint16_t dindex, bc;
+ uint16_t ndialects;
+ boolean_t will_sign = B_FALSE;
+
+ /*
+ * Initialize: vc_hflags and vc_hflags2.
+ * Note: vcp->vc_hflags* are copied into the
+ * (per request) rqp->rq_hflags* by smb_rq_init.
+ *
+ * Like Windows, set FLAGS2_UNICODE in our first request,
+ * even though technically we don't yet know whether the
+ * server supports Unicode. Will clear this flag below
+ * if we find out it doesn't. Need to do this because
+ * some servers reject all non-Unicode requests.
+ */
+ vcp->vc_hflags =
+ SMB_FLAGS_CASELESS |
+ SMB_FLAGS_CANONICAL_PATHNAMES;
+ vcp->vc_hflags2 =
+ SMB_FLAGS2_KNOWS_LONG_NAMES |
+ SMB_FLAGS2_KNOWS_EAS |
+ SMB_FLAGS2_IS_LONG_NAME |
+ SMB_FLAGS2_EXT_SEC |
+ SMB_FLAGS2_ERR_STATUS |
+ SMB_FLAGS2_UNICODE;
+
+ /*
+ * The initial UID needs to be zero,
+ */
+ vcp->vc_smbuid = 0;
+
+ /*
+ * (Re)init negotiated values
+ */
+ bzero(sv, sizeof (*sv));
+ sv->sv_maxmux = 1;
+ sv->sv_maxvcs = 1;
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Should we offer the magic SMB2 dialect?
+ */
+ if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE)
+ ndialects = NDIALECT_SMB2;
+ else
+ ndialects = NDIALECT_SMB1;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ for (dindex = 0; dindex < ndialects; dindex++) {
+ dp = &smb_dialects[dindex];
+ mb_put_uint8(mbp, SMB_DT_DIALECT);
+ tlen = strlen(dp->d_name) + 1;
+ mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM);
+ }
+ smb_rq_bend(rqp);
+
+ /*
+ * Do the OTW call.
+ */
+ err = smb_rq_internal(rqp, smb_timo_default);
+ /*
+ * If it's an SMB1-to-SMB2 negotiate response,
+ * call the special handler and then skip the
+ * whole rest of this function.
+ */
+ if (err == EPROTO) {
+ err = smb2_parse_smb1nego_resp(rqp);
+ smb_rq_done(rqp);
+ return (err);
+ }
+ if (err) {
+ SMBSDEBUG("smb_rq_internal, err %d", err);
+ goto errout;
+ }
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Decode the response
+ *
+ * Comments to right show names as described in
+ * The Microsoft SMB Protocol spec. [MS-SMB]
+ * section 2.2.3
+ */
+ smb_rq_getreply(rqp, &mdp);
+ (void) md_get_uint8(mdp, &wc);
+ err = md_get_uint16le(mdp, &dindex);
+ if (err != 0)
+ goto errout;
+ if (dindex >= ndialects) {
+ SMBERROR("Invalid dialect index from server: %s\n",
+ vcp->vc_srvname);
+ err = EBADRPC;
+ goto errout;
+ }
+ dp = smb_dialects + dindex;
+ sv->sv_proto = dp->d_id;
+ SMBSDEBUG("Dialect %s", dp->d_name);
+ if (dp->d_id < SMB_DIALECT_NTLM0_12) {
+ SMBSDEBUG("old dialect %s", dp->d_name);
+ goto errout;
+ }
+ if (wc != 17) {
+ SMBSDEBUG("bad wc %d", (int)wc);
+ goto errout;
+ }
+ md_get_uint8(mdp, &sv->sv_sm); /* SecurityMode */
+ md_get_uint16le(mdp, &sv->sv_maxmux); /* MaxMpxCount */
+ md_get_uint16le(mdp, &sv->sv_maxvcs); /* MaxCountVCs */
+ md_get_uint32le(mdp, &sv->sv_maxtx); /* MaxBufferSize */
+ md_get_uint32le(mdp, &sv->sv_maxraw); /* MaxRawSize */
+ md_get_uint32le(mdp, &sv->sv_skey); /* SessionKey */
+ md_get_uint32le(mdp, &sv->sv_caps); /* Capabilities */
+ md_get_mem(mdp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
+ md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz);
+ md_get_uint8(mdp, &eklen); /* EncryptionKeyLength */
+ err = md_get_uint16le(mdp, &bc); /* ByteCount */
+ if (err)
+ goto errout;
+
+ /* BEGIN CSTYLED */
+ /*
+ * Will we do SMB signing? Or block the connection?
+ * The table below describes this logic. References:
+ * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
+ * http://msdn.microsoft.com/en-us/library/cc212511.aspx
+ * http://msdn.microsoft.com/en-us/library/cc212929.aspx
+ *
+ * Srv/Cli | Required | Enabled | If Required | Disabled
+ * ------------+----------+------------+-------------+-----------
+ * Required | Signed | Signed | Signed | Blocked [1]
+ * ------------+----------+------------+-------------+-----------
+ * Enabled | Signed | Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * If Required | Signed | Not Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * Disabled | Blocked | Not Signed | Not Signed | Not Signed
+ *
+ * [1] Like Windows 2003 and later, we don't really implement
+ * the "Disabled" setting. Instead we implement "If Required",
+ * so we always sign if the server requires signing.
+ */
+ /* END CSTYLED */
+
+ if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
+ /*
+ * Server requires signing. We will sign,
+ * even if local setting is "disabled".
+ */
+ will_sign = B_TRUE;
+ } else if (sv->sv_sm & SMB_SM_SIGS) {
+ /*
+ * Server enables signing (client's option).
+ * If enabled locally, do signing.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
+ will_sign = B_TRUE;
+ /* else not signing. */
+ } else {
+ /*
+ * Server does not support signing.
+ * If we "require" it, bail now.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ SMBERROR("Client requires signing "
+ "but server has it disabled.");
+ err = EBADRPC;
+ goto errout;
+ }
+ }
+
+ /*
+ * Anonymous sessions can't sign.
+ */
+ if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) {
+ will_sign = B_FALSE;
+ }
+
+ SMBSDEBUG("Security signatures: %d", (int)will_sign);
+ if (will_sign) {
+ vcp->vc_flags |= SMBV_SIGNING;
+ vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+
+ /*
+ * MS-SMB 2.2.4.5 says that when SMB signing is enabled,
+ * we should NOT use "large read/write" even though the
+ * server might offer those capabilities.
+ */
+ sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
+ }
+
+ /* See comment above re. FLAGS2_UNICODE */
+ if ((sv->sv_caps & SMB_CAP_UNICODE) != 0)
+ vcp->vc_flags |= SMBV_UNICODE;
+ else
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
+
+ if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
+ /* They don't do NT error codes. */
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
+ }
+
+ /*
+ * Warn if they don't support SMB_CAP_NT_SMBS
+ * (We'll try to use NtCreate anyway)
+ */
+ if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
+ cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS",
+ vcp->vc_srvname);
+ }
+
+ /*
+ * The rest of the message varies depending on
+ * whether we've negotiated "extended security".
+ *
+ * With extended security, we have:
+ * Server_GUID (length 16)
+ * Security_BLOB
+ * Otherwise we have:
+ * EncryptionKey (length is eklen)
+ * PrimaryDomain
+ */
+ if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
+ SMBSDEBUG("Ext.Security: yes");
+
+ /*
+ * Skip the server GUID.
+ */
+ err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
+ if (err)
+ goto errout;
+ /*
+ * Remainder is the security blob.
+ * Note: eklen "must be ignored" [MS-SMB]
+ */
+ sblen = (int)bc - SMB_GUIDLEN;
+ if (sblen < 0)
+ goto errout;
+ /* Security blob (hint) is next */
+ } else {
+ SMBSDEBUG("Ext.Security: no");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sblen) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sblen;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sblen;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER);
+ if (err)
+ goto errout;
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sv->sv_maxmux < 1)
+ sv->sv_maxmux = 1;
+ if (sv->sv_maxvcs < 1)
+ sv->sv_maxvcs = 1;
+ if (sv->sv_maxtx < 1024)
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Maximum transfer size.
+ * Sanity checks:
+ *
+ * Let's be conservative about an upper limit here.
+ * Win2k uses 16644 (and others) so 32k should be a
+ * reasonable sanity limit for this value.
+ *
+ * Note that this limit does NOT affect READX/WRITEX
+ * with CAP_LARGE_..., which we nearly always use.
+ */
+ vcp->vc_txmax = sv->sv_maxtx;
+ if (vcp->vc_txmax > 0x8000)
+ vcp->vc_txmax = 0x8000;
+
+ /*
+ * Max read/write sizes, WITHOUT overhead.
+ * This is just the payload size, so we must
+ * leave room for the SMB headers, etc.
+ * This is just the ct_txmax value, but
+ * reduced and rounded down. Tricky bit:
+ *
+ * Servers typically give us a value that's
+ * some nice "round" number, i.e 0x4000 plus
+ * some overhead, i.e. Win2k: 16644==0x4104
+ * Subtract for the SMB header (32) and the
+ * SMB command word and byte vectors (34?),
+ * then round down to a 512 byte multiple.
+ */
+ tlen = vcp->vc_txmax - 68;
+ tlen &= 0xFE00;
+
+ vcp->vc_rwmax = tlen;
+ vcp->vc_rxmax = tlen;
+ vcp->vc_wxmax = tlen;
+
+ /*
+ * Most of the "capability" bits we offer in session setup
+ * are just copied from those offered by the server.
+ */
+ sv->sv_caps &= smb_clnt_caps_mask;
+
+ smb_rq_done(rqp);
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
+
+static const char NativeOS[] = "illumos";
+static const char LanMan[] = "NETSMB";
+
+int
+smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ char *sb;
+ int err, ret;
+ uint32_t caps;
+ uint16_t action, bc, sblen;
+ uint8_t wc;
+
+ caps = sv->sv_caps;
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
+ scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Build the SMB Session Setup request.
+ * Always extended security form.
+ */
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
+ mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
+ mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
+ mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
+ mb_put_uint16le(mbp, 1); /* 4: VcNumber */
+ mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
+ mb_put_uint16le(mbp, sblen); /* 7: Sec. Blob Len */
+ mb_put_uint32le(mbp, 0); /* 8,9: reserved */
+ mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
+ smb_rq_wend(rqp); /* 12: Byte Count */
+ smb_rq_bstart(rqp);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE);
+ (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE);
+ smb_rq_bend(rqp);
+
+ /*
+ * Run the request. The return value here should be the
+ * return from this function, unless we fail decoding.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
+ */
+ ret = smb_rq_internal(rqp, smb_timo_logon);
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
+ goto out;
+ }
+
+ if (vcp->vc_smbuid == 0)
+ vcp->vc_smbuid = rqp->sr_rpuid;
+
+ /*
+ * Parse the reply
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ err = md_get_uint8(mdp, &wc);
+ if (err != 0)
+ wc = 0;
+ if (wc != 4) {
+ ret = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* secondary cmd */
+ md_get_uint16le(mdp, NULL); /* andxoffset */
+ md_get_uint16le(mdp, &action); /* action XXX */
+ md_get_uint16le(mdp, &sblen); /* sec. blob len */
+ md_get_uint16le(mdp, &bc); /* byte count */
+ /*
+ * Get the security blob, after
+ * sanity-checking the length.
+ */
+ if (sblen == 0 || sblen > bc) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (sblen > wk->wk_u_auth_rlen) {
+ ret = EBADRPC;
+ goto out;
+ }
+ sb = wk->wk_u_auth_rbuf.lp_ptr;
+ err = md_get_mem(mdp, sb, sblen, MB_MUSER);
+ if (err) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ /*
+ * Native OS, LANMGR, & Domain follow here.
+ * We don't need them and don't parse them.
+ */
+
+out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* UID no longer valid. */
+ vcp->vc_smbuid = 0;
+ }
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+}
+
+int
+smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
+ if (error)
+ return (error);
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff);
+ mb_put_uint8(mbp, 0);
+ mb_put_uint16le(mbp, 0);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
-static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+}
/*
* Get the string representation of a share "use" type,
@@ -352,7 +871,7 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
* Modern create/open of file or directory.
*/
int
-smb_smb_ntcreate(
+smb1_smb_ntcreate(
struct smb_share *ssp,
struct mbchain *name_mb,
uint32_t cr_flags, /* create flags */
@@ -475,7 +994,7 @@ done:
}
int
-smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
+smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
struct smb_cred *scrp)
{
struct smb_rq rq, *rqp = &rq;
@@ -600,101 +1119,11 @@ smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
return (error);
}
-/*
- * Common function for read/write with UIO.
- * Called by netsmb smb_usr_rw,
- * smbfs_readvnode, smbfs_writevnode
- */
int
-smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_vc *vcp = SSTOVC(ssp);
- ssize_t save_resid;
- uint32_t len, rlen, maxlen;
- int error = 0;
- int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
- uio_t *, smb_cred_t *, int);
-
- /*
- * Determine which function to use,
- * and the transfer size per call.
- */
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
- /*
- * Using NT LM 0.12, so readx, writex.
- * Make sure we can represent the offset.
- */
- if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
- (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
- return (EFBIG);
-
- if (rw == UIO_READ) {
- iofun = smb_smb_readx;
- if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
- maxlen = SMB_MAX_LARGE_RW_SIZE;
- else
- maxlen = vcp->vc_rxmax;
- } else { /* UIO_WRITE */
- iofun = smb_smb_writex;
- if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
- maxlen = SMB_MAX_LARGE_RW_SIZE;
- else
- maxlen = vcp->vc_wxmax;
- }
- } else {
- /*
- * Using the old SMB_READ and SMB_WRITE so
- * we're limited to 32-bit offsets, etc.
- * XXX: Someday, punt the old dialects.
- */
- if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
- return (EFBIG);
-
- if (rw == UIO_READ) {
- iofun = smb_smb_read;
- maxlen = vcp->vc_rxmax;
- } else { /* UIO_WRITE */
- iofun = smb_smb_write;
- maxlen = vcp->vc_wxmax;
- }
- }
-
- save_resid = uiop->uio_resid;
- while (uiop->uio_resid > 0) {
- /* Lint: uio_resid may be 64-bits */
- rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
- error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
-
- /*
- * Note: the iofun called uio_update, so
- * not doing that here as one might expect.
- *
- * Quit the loop either on error, or if we
- * transferred less then requested.
- */
- if (error || (rlen < len))
- break;
-
- timo = 0; /* only first I/O should wait */
- }
- if (error && (save_resid != uiop->uio_resid)) {
- /*
- * Stopped on an error after having
- * successfully transferred data.
- * Suppress this error.
- */
- SMBSDEBUG("error %d suppressed\n", error);
- error = 0;
- }
-
- return (error);
-}
-
-static int
-smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
+smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
@@ -716,7 +1145,7 @@ smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint16le(mbp, lenlo); /* MaxCount */
mb_put_uint16le(mbp, 1); /* MinCount */
@@ -786,10 +1215,11 @@ out:
return (error);
}
-static int
-smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
+int
+smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
@@ -811,7 +1241,7 @@ smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
mb_put_uint16le(mbp, 0); /* !write-thru */
@@ -859,148 +1289,13 @@ out:
return (error);
}
-static int
-smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t bc, cnt, dlen, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned reads. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
-
- if (timo == 0)
- timo = smb_timo_read;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 5) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &rcnt); /* ret. count */
- md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */
- md_get_uint16le(mdp, &bc); /* byte count */
- md_get_uint8(mdp, NULL); /* buffer format */
- error = md_get_uint16le(mdp, &dlen); /* data len */
- if (error)
- goto out;
- if (dlen < rcnt) {
- SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
- (int)dlen, (int)rcnt);
- rcnt = dlen;
- }
- if (rcnt == 0) {
- *lenp = 0;
- goto out;
- }
- /* paranoid */
- if (rcnt > cnt) {
- SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
- (int)rcnt, (int)cnt);
- rcnt = cnt;
- }
- error = md_get_uio(mdp, uiop, (int)rcnt);
- if (error)
- goto out;
-
- /* success */
- *lenp = (int)rcnt;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-static int
-smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t cnt, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned writes. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, cnt);
-
- error = mb_put_uio(mbp, uiop, *lenp);
- if (error)
- goto out;
- smb_rq_bend(rqp);
- if (timo == 0)
- timo = smb_timo_write;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, &rcnt);
- if (error)
- goto out;
- *lenp = rcnt;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
static u_int32_t smbechoes = 0;
+/*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb_rq_internal)
+ */
int
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
{
@@ -1018,13 +1313,8 @@ smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
smb_rq_bstart(rqp);
mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
smb_rq_bend(rqp);
- /*
- * Note: the IOD calls this, so
- * this request must not wait for
- * connection state changes, etc.
- */
rqp->sr_flags |= SMBR_NORECONNECT;
- error = smb_rq_simple_timed(rqp, timo);
+ error = smb_rq_internal(rqp, timo);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
return (error);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
index df0f28ec05..b780f9b21b 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
@@ -33,8 +33,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_SUBR_H_
@@ -43,8 +43,16 @@
#include <sys/cmn_err.h>
#include <sys/lock.h>
#include <sys/note.h>
+#include <netsmb/mchain.h>
#include <netsmb/smb_conn.h>
+/*
+ * Possible lock commands
+ */
+#define SMB_LOCK_EXCL 0
+#define SMB_LOCK_SHARED 1
+#define SMB_LOCK_RELEASE 2
+
struct msgb; /* avoiding sys/stream.h here */
/* Helper function for SMBERROR */
@@ -117,86 +125,131 @@ extern int smb_timo_open;
extern int smb_timo_read;
extern int smb_timo_write;
extern int smb_timo_append;
+extern dev_t nsmb_dev_tcp;
+extern dev_t nsmb_dev_tcp6;
-#define EMOREDATA (0x7fff)
+/*
+ * Tunable timeout values. See: smb2_smb.c
+ */
+extern int smb2_timo_notice;
+extern int smb2_timo_default;
+extern int smb2_timo_open;
+extern int smb2_timo_read;
+extern int smb2_timo_write;
+extern int smb2_timo_append;
void smb_credinit(struct smb_cred *scred, cred_t *cr);
void smb_credrele(struct smb_cred *scred);
-void smb_oldlm_hash(const char *apwd, uchar_t *hash);
-void smb_ntlmv1hash(const char *apwd, uchar_t *hash);
-void smb_ntlmv2hash(const uchar_t *v1hash, const char *user,
- const char *destination, uchar_t *v2hash);
-
-int smb_lmresponse(const uchar_t *hash, const uchar_t *C8, uchar_t *RN);
-int smb_ntlmv2response(const uchar_t *hash, const uchar_t *C8,
- const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen);
int smb_maperror(int eclass, int eno);
int smb_maperr32(uint32_t eno);
+uint_t smb_doserr2status(int, int);
+int smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp,
+ char *outbuf, size_t *outlen, int inlen);
int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int len, int caseopt, int *lenp);
int smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int caseopt);
int smb_put_string(struct smb_rq *rqp, const char *src);
int smb_put_asunistring(struct smb_rq *rqp, const char *src);
-int smb_checksmp(void);
+
+int smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb_fh_t *fhp,
+ uint32_t *cr_act_p, struct smbfattr *fap);
+
+int smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp);
+
+int smb_rwuio(smb_fh_t *fhp, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo);
int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *);
struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa);
void smb_free_sockaddr(struct sockaddr *sa);
-int smb_toupper(const char *, char *, size_t);
+int smb_sign_init(struct smb_vc *);
void smb_rq_sign(struct smb_rq *);
int smb_rq_verify(struct smb_rq *);
int smb_calcv2mackey(struct smb_vc *, const uchar_t *,
const uchar_t *, size_t);
int smb_calcmackey(struct smb_vc *, const uchar_t *,
const uchar_t *, size_t);
-void smb_crypto_mech_init(void);
+int smb2_sign_init(struct smb_vc *);
+void smb2_rq_sign(struct smb_rq *);
+int smb2_rq_verify(struct smb_rq *);
/*
* SMB protocol level functions
*/
+int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
+int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
+int smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred);
int smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
-int
-smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+int smb1_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
uint32_t disp, uint32_t createopt, uint32_t impersonate,
struct smb_cred *scrp, uint16_t *fidp,
uint32_t *cr_act_p, struct smbfattr *fap);
-int smb_smb_close(struct smb_share *ssp, uint16_t fid,
+int smb1_smb_close(struct smb_share *ssp, uint16_t fid,
struct timespec *mtime, struct smb_cred *scrp);
-int
-smb_smb_open_prjob(struct smb_share *ssp, char *title,
+int smb_smb_open_prjob(struct smb_share *ssp, char *title,
uint16_t setuplen, uint16_t mode,
struct smb_cred *scrp, uint16_t *fidp);
int smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
struct smb_cred *scrp);
-int smb_rwuio(smb_share_t *ssp, uint16_t fid, uio_rw_t rw,
+int smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
+int smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo);
/*
- * time conversions
+ * SMB2 protocol level functions
*/
+int smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
+int smb2_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
+int smb2_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
+
+int
+smb2_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ struct mbchain *cctx_in, struct mdchain *cctx_out,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb2fid_t *fidp,
+ uint32_t *cr_act_p, struct smbfattr *fap);
+
+int smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp);
+
+int smb2_smb_ioctl(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *data_in, struct mdchain *data_out,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t ctl_code, struct smb_cred *scrp);
+
+int smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
+int smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
-void smb_time_init(void);
-void smb_time_fini(void);
+/*
+ * time conversions
+ */
void smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds);
void smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp);
void smb_time_NT2local(uint64_t nsec, struct timespec *tsp);
void smb_time_local2NT(struct timespec *tsp, uint64_t *nsec);
-void smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp,
- uint16_t *dtp, uint8_t *dhp);
-void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
- struct timespec *tsp);
#endif /* !_NETSMB_SMB_SUBR_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
index e29a96631a..bf1e605187 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
@@ -34,6 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -57,50 +59,19 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb_subr.h>
-/*
- * XXX:This conversion might not be fully MS-Compatible
- * for calculating hashes. The output length may differ
- * for some locales and needs to be handled from where
- * the call is made.
- */
-int
-smb_toupper(const char *inbuf, char *outbuf, size_t outlen)
-{
- int err = 0;
- size_t inlen, inrem, outrem;
-
- inrem = inlen = strlen(inbuf);
- outrem = outlen;
- (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem,
- U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
- /* inrem, outrem are bytes unused, remaining */
- if (inrem) {
- SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf);
- inlen -= inrem;
- }
- if (outrem) {
- outlen -= outrem;
- outbuf[outlen] = '\0';
- }
- if (outlen > inlen) {
- SMBSDEBUG("outlen > inlen! (%d > %d)\n",
- (int)outlen, (int)inlen);
- /* Truncate to inlen here? */
- }
-
- return (err);
-}
-
void
smb_credinit(struct smb_cred *scred, cred_t *cr)
{
/* cr arg is optional */
if (cr == NULL)
cr = ddi_get_cred();
+#ifdef _KERNEL
if (is_system_labeled()) {
cr = crdup(cr);
(void) setpflags(NET_MAC_AWARE, 1, cr);
- } else {
+ } else
+#endif
+ {
crhold(cr);
}
scred->scr_cred = cr;
@@ -115,6 +86,14 @@ smb_credrele(struct smb_cred *scred)
}
}
+#ifndef _KERNEL
+/* ARGSUSED */
+void
+smb_debugmsg(const char *func, char *msg)
+{
+}
+#endif /* _KERNEL */
+
/*
* Helper for the SMBERROR macro, etc.
* This is also a good place for a breakpoint
@@ -137,6 +116,9 @@ smb_errmsg(int cel, const char *func_name, const char *fmt, ...)
DTRACE_PROBE2(debugmsg2,
(char *), func_name,
(char *), buf);
+#ifndef _KERNEL
+ smb_debugmsg(func_name, buf);
+#endif
} else {
/*
* This is one of our xxxERROR macros.
@@ -190,6 +172,9 @@ m_dumpm(mblk_t *m)
#ifndef ETIME
#define ETIME ETIMEDOUT
#endif
+#ifndef EMOREDATA
+#define EMOREDATA (0x7fff)
+#endif
/*
* Log any un-handled NT or DOS errors we encounter.
@@ -219,7 +204,9 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
{NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
{NT_STATUS_BAD_NETWORK_NAME, ENOENT},
- {NT_STATUS_BUFFER_TOO_SMALL, EMOREDATA},
+ {NT_STATUS_BAD_NETWORK_PATH, ENOENT},
+ {NT_STATUS_BUFFER_TOO_SMALL, E2BIG},
+ {NT_STATUS_CANCELLED, ECANCELED},
{NT_STATUS_CANNOT_DELETE, EACCES},
{NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
{NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
@@ -233,59 +220,87 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_DISK_FULL, ENOSPC},
{NT_STATUS_DLL_NOT_FOUND, ELIBACC},
{NT_STATUS_DUPLICATE_NAME, EINVAL},
+ {NT_STATUS_EAS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_EA_TOO_LARGE, E2BIG},
{NT_STATUS_END_OF_FILE, ENODATA},
+ {NT_STATUS_FILE_CLOSED, EBADF},
+ {NT_STATUS_FILE_DELETED, ENOENT},
+ {NT_STATUS_FILE_INVALID, EIO},
{NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
{NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN},
+ {NT_STATUS_FILE_RENAMED, ENOENT},
{NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
{NT_STATUS_FLOAT_OVERFLOW, ERANGE},
{NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
{NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
- {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EAUTH},
+ {NT_STATUS_INFO_LENGTH_MISMATCH, EINVAL},
+ {NT_STATUS_INSUFFICIENT_RESOURCES, EAGAIN},
+ {NT_STATUS_INSUFF_SERVER_RESOURCES, EAGAIN},
{NT_STATUS_INTEGER_OVERFLOW, ERANGE},
- {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES},
+ {NT_STATUS_INVALID_ACCOUNT_NAME, EAUTH},
+ {NT_STATUS_INVALID_BUFFER_SIZE, EIO},
+ {NT_STATUS_INVALID_DEVICE_REQUEST, EINVAL},
{NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_INVALID_INFO_CLASS, EINVAL},
{NT_STATUS_INVALID_LEVEL, ENOTSUP},
- {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_INVALID_LOCK_SEQUENCE, EINVAL},
+ {NT_STATUS_INVALID_LOGON_HOURS, EAUTH},
{NT_STATUS_INVALID_OWNER, EINVAL},
{NT_STATUS_INVALID_PARAMETER, EINVAL},
{NT_STATUS_INVALID_PIPE_STATE, EPIPE},
{NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL},
{NT_STATUS_INVALID_WORKSTATION, EACCES},
{NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_IO_DEVICE_ERROR, EIO},
{NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
- {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
- {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, EADDRINUSE},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, EADDRINUSE},
{NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
{NT_STATUS_LOCK_NOT_GRANTED, EAGAIN},
- {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES},
- {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_LOGIN_TIME_RESTRICTION, EAUTH},
+ {NT_STATUS_LOGON_FAILURE, EAUTH},
+ {NT_STATUS_LOGON_TYPE_NOT_GRANTED, EAUTH},
{NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
{NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_MORE_PROCESSING_REQUIRED, EINPROGRESS},
{NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
{NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
{NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_NETWORK_NAME_DELETED, ENOENT},
{NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
{NT_STATUS_NET_WRITE_FAULT, ECOMM},
+ {NT_STATUS_NONEXISTENT_EA_ENTRY, ENOENT},
{NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
{NT_STATUS_NONE_MAPPED, EINVAL},
{NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_NOT_FOUND, ENOENT},
{NT_STATUS_NOT_IMPLEMENTED, ENOTSUP},
+ {NT_STATUS_NOT_LOCKED, ENOLCK},
{NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
{NT_STATUS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_NO_EAS_ON_FILE, ENOENT},
+ {NT_STATUS_NO_LOGON_SERVERS, EAUTH},
{NT_STATUS_NO_MEDIA, ENOMEDIUM},
{NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
{NT_STATUS_NO_MEMORY, ENOMEM},
{NT_STATUS_NO_SUCH_DEVICE, ENODEV},
{NT_STATUS_NO_SUCH_FILE, ENOENT},
+ {NT_STATUS_NO_SUCH_LOGON_SESSION, EAUTH},
+ {NT_STATUS_NO_SUCH_USER, EAUTH},
+ {NT_STATUS_NO_TRUST_LSA_SECRET, EAUTH},
+ {NT_STATUS_NO_TRUST_SAM_ACCOUNT, EAUTH},
{NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
{NT_STATUS_OBJECT_NAME_INVALID, EINVAL},
{NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
{NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
{NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_SYNTAX_BAD, EINVAL},
+ {NT_STATUS_OBJECT_TYPE_MISMATCH, EBADF},
{NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
- {NT_STATUS_PASSWORD_EXPIRED, EACCES},
- {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES},
- {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EAUTH},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, EAUTH},
+ {NT_STATUS_PASSWORD_RESTRICTION, EAUTH},
{NT_STATUS_PATH_NOT_COVERED, ENOENT},
{NT_STATUS_PIPE_BROKEN, EPIPE},
{NT_STATUS_PIPE_BUSY, EPIPE},
@@ -293,11 +308,12 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_PIPE_DISCONNECTED, EPIPE},
{NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY},
{NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_PORT_DISCONNECTED, EBADF},
{NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
{NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
{NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
{NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
- {NT_STATUS_RANGE_NOT_LOCKED, EIO},
+ {NT_STATUS_RANGE_NOT_LOCKED, EAGAIN}, /* like F_SETLK */
{NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
{NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
{NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
@@ -307,9 +323,11 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_TIMER_NOT_CANCELED, ETIME},
{NT_STATUS_TOO_MANY_LINKS, EMLINK},
{NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+ {NT_STATUS_TRUSTED_DOMAIN_FAILURE, EAUTH},
+ {NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE, EAUTH},
{NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
{NT_STATUS_UNSUCCESSFUL, EINVAL},
- {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_WRONG_PASSWORD, EAUTH},
{0, 0}
};
@@ -593,14 +611,6 @@ static const nt2doserr_t nt2doserr[] = {
{ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION},
{ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE},
{ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR},
{ERRHRD, ERRgeneral, NT_STATUS_NO_LDT},
{ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE},
{ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET},
@@ -868,6 +878,19 @@ smb_maperr32(uint32_t nterr)
return (EIO);
}
+uint_t
+smb_doserr2status(int dclass, int derr)
+{
+ const nt2doserr_t *nt2d;
+
+ if (dclass == 0 && derr == 0)
+ return (0);
+
+ for (nt2d = nt2doserr; nt2d->nterr; nt2d++)
+ if (nt2d->dclass == dclass && nt2d->derr == derr)
+ return (nt2d->nterr);
+ return (NT_STATUS_UNSUCCESSFUL);
+}
int
smb_maperror(int eclass, int eno)
@@ -996,13 +1019,90 @@ smb_maperror(int eclass, int eno)
return (EIO);
}
-#if defined(NOICONVSUPPORT) || defined(lint)
-extern int iconv_conv(void *handle, const char **inbuf,
- size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
-#endif
-
#define SMALL_CONV 256
+/*
+ * Decode an SMB OTW string (Unicode or OEM chars)
+ * converting to UTF-8 in the output buffer.
+ * outlen is in/out (max size on input)
+ * insize is the wire size (2 * chars if unicode)
+ * The output string is null terminated.
+ * Output length does not include the null.
+ */
+int
+smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp,
+ char *outbuf, size_t *outlen, int insize)
+{
+ uint16_t convbuf[SMALL_CONV];
+ uint16_t *cbuf;
+ size_t cbufalloc, inlen, outsize;
+ int error;
+
+ if (insize <= 0)
+ return (0);
+ /* Note: inlen is UTF-16 symbols. */
+ inlen = insize / 2;
+
+ if (*outlen < 2)
+ return (EINVAL);
+ outsize = *outlen - 1; /* room for null */
+
+ /*
+ * Get a buffer for the conversion and fill it.
+ * Use stack buffer if the string is
+ * small enough, else allocate.
+ */
+ if (insize < sizeof (convbuf)) {
+ cbufalloc = 0;
+ cbuf = convbuf;
+ } else {
+ cbufalloc = insize + 2;
+ cbuf = kmem_alloc(cbufalloc, KM_SLEEP);
+ }
+ error = md_get_mem(mdc, cbuf, insize, MB_MSYSTEM);
+ if (error != 0)
+ goto out;
+ cbuf[inlen] = 0;
+
+ /*
+ * Handle the easy case (non-unicode).
+ * XXX: Technically, we should convert
+ * the string to OEM codeset first...
+ * Modern servers all use Unicode, so
+ * this is good enough.
+ */
+ if (SMB_UNICODE_STRINGS(vcp) == 0) {
+ *outlen = strlcpy(outbuf, (char *)cbuf, outsize);
+ if (*outlen > outsize) {
+ *outlen = outsize;
+ error = E2BIG;
+ }
+ } else {
+ /*
+ * Convert from UTF-16 to UTF-8
+ */
+ error = uconv_u16tou8(cbuf, &inlen,
+ (uchar_t *)outbuf, outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ if (error == 0) {
+ outbuf[*outlen] = '\0';
+ }
+ }
+
+ ASSERT(*outlen == strlen(outbuf));
+
+out:
+ if (cbufalloc != 0)
+ kmem_free(cbuf, cbufalloc);
+
+ return (error);
+}
+
+/*
+ * It's surprising that this function does utf8-ucs2 conversion.
+ * One would expect only smb_put_dstring to do that.
+ * Fixing that will require changing a bunch of callers. XXX
+ */
/*ARGSUSED*/
int
smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
@@ -1080,3 +1180,130 @@ smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
return (error);
}
+int
+smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb_fh_t *fhp,
+ uint32_t *cr_act_p, struct smbfattr *fap)
+{
+ int err;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ntcreate(ssp, name_mb, NULL, NULL,
+ crflag, req_acc, efa, sh_acc, disp, createopt,
+ impersonate, scrp, &fhp->fh_fid2, cr_act_p, fap);
+ } else {
+ err = smb1_smb_ntcreate(ssp, name_mb, crflag, req_acc,
+ efa, sh_acc, disp, createopt, impersonate, scrp,
+ &fhp->fh_fid1, cr_act_p, fap);
+ }
+ return (err);
+}
+
+int
+smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+{
+ int err;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_close(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ err = smb1_smb_close(ssp, fhp->fh_fid1, NULL, scrp);
+ }
+
+ return (err);
+}
+
+/*
+ * Largest size to use with LARGE_READ/LARGE_WRITE.
+ * Specs say up to 64k data bytes, but Windows traffic
+ * uses 60k... no doubt for some good reason.
+ * (Probably to keep 4k block alignment.)
+ */
+uint32_t smb1_large_io_max = (60*1024);
+
+/*
+ * Common function for read/write with UIO.
+ * Called by netsmb smb_usr_rw,
+ * smbfs_readvnode, smbfs_writevnode
+ */
+int
+smb_rwuio(smb_fh_t *fhp, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_vc *vcp = SSTOVC(ssp);
+ ssize_t save_resid;
+ uint32_t len, rlen, maxlen;
+ int error = 0;
+ int (*iofun)(smb_fh_t *, uint32_t *,
+ uio_t *, smb_cred_t *, int);
+
+ /* After reconnect, the fid is invalid. */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ if (rw == UIO_READ) {
+ iofun = smb2_smb_read;
+ maxlen = vcp->vc_sopt.sv2_maxread;
+ } else { /* UIO_WRITE */
+ iofun = smb2_smb_write;
+ maxlen = vcp->vc_sopt.sv2_maxwrite;
+ }
+ } else {
+ /*
+ * Using NT LM 0.12, so readx, writex.
+ * Make sure we can represent the offset.
+ */
+ if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
+ (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
+ return (EFBIG);
+
+ if (rw == UIO_READ) {
+ iofun = smb_smb_readx;
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
+ maxlen = smb1_large_io_max;
+ else
+ maxlen = vcp->vc_rxmax;
+ } else { /* UIO_WRITE */
+ iofun = smb_smb_writex;
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
+ maxlen = smb1_large_io_max;
+ else
+ maxlen = vcp->vc_wxmax;
+ }
+ }
+
+ save_resid = uiop->uio_resid;
+ while (uiop->uio_resid > 0) {
+ /* Lint: uio_resid may be 64-bits */
+ rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
+ error = (*iofun)(fhp, &rlen, uiop, scred, timo);
+
+ /*
+ * Note: the iofun called uio_update, so
+ * not doing that here as one might expect.
+ *
+ * Quit the loop either on error, or if we
+ * transferred less then requested.
+ */
+ if (error || (rlen < len))
+ break;
+
+ timo = 0; /* only first I/O should wait */
+ }
+ if (error && (save_resid != uiop->uio_resid)) {
+ /*
+ * Stopped on an error after having
+ * successfully transferred data.
+ * Suppress this error.
+ */
+ SMBSDEBUG("error %d suppressed\n", error);
+ error = 0;
+ }
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
index e984ded911..0116d6ea6e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -55,61 +57,6 @@
#include <netsmb/smb_subr.h>
/*
- * Time & date conversion routines taken from msdosfs. Although leap
- * year calculation is bogus, it's sufficient before 2100 :)
- */
-/*
- * This is the format of the contents of the deTime field in the direntry
- * structure.
- * We don't use bitfields because we don't know how compilers for
- * arbitrary machines will lay them out.
- */
-#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
-#define DT_2SECONDS_SHIFT 0
-#define DT_MINUTES_MASK 0x7E0 /* minutes */
-#define DT_MINUTES_SHIFT 5
-#define DT_HOURS_MASK 0xF800 /* hours */
-#define DT_HOURS_SHIFT 11
-
-/*
- * This is the format of the contents of the deDate field in the direntry
- * structure.
- */
-#define DD_DAY_MASK 0x1F /* day of month */
-#define DD_DAY_SHIFT 0
-#define DD_MONTH_MASK 0x1E0 /* month */
-#define DD_MONTH_SHIFT 5
-#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
-#define DD_YEAR_SHIFT 9
-/*
- * Total number of days that have passed for each month in a regular year.
- */
-static ushort_t regyear[] = {
- 31, 59, 90, 120, 151, 181,
- 212, 243, 273, 304, 334, 365
-};
-
-/*
- * Total number of days that have passed for each month in a leap year.
- */
-static ushort_t leapyear[] = {
- 31, 60, 91, 121, 152, 182,
- 213, 244, 274, 305, 335, 366
-};
-
-/*
- * Variables used to remember parts of the last time conversion. Maybe we
- * can avoid a full conversion.
- */
-static ulong_t lasttime;
-static ulong_t lastday;
-static ushort_t lastddate;
-static ushort_t lastdtime;
-
-/* Lock for the lastxxx variables */
-static kmutex_t lastdt_lock;
-
-/*
* Number of seconds between 1970 and 1601 year
* (134774 days)
*/
@@ -193,161 +140,3 @@ smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp)
tsp->tv_sec = seconds + tzoff * 60;
tsp->tv_nsec = 0;
}
-
-/*
- * Time conversions to/from DOS format, for old dialects.
- */
-
-void
-smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
- u_int16_t *dtp, u_int8_t *dhp)
-{
- long t;
- ulong_t days, year, month, inc;
- ushort_t *months;
-
- mutex_enter(&lastdt_lock);
-
- /*
- * If the time from the last conversion is the same as now, then
- * skip the computations and use the saved result.
- */
- smb_time_local2server(tsp, tzoff, &t);
- t &= ~1;
- if (lasttime != t) {
- lasttime = t;
- if (t < 0) {
- /*
- * This is before 1970, so it's before 1980,
- * and can't be represented as a DOS time.
- * Just represent it as the DOS epoch.
- */
- lastdtime = 0;
- lastddate = (1 << DD_DAY_SHIFT)
- + (1 << DD_MONTH_SHIFT)
- + ((1980 - 1980) << DD_YEAR_SHIFT);
- } else {
- lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
- + (((t / 60) % 60) << DT_MINUTES_SHIFT)
- + (((t / 3600) % 24) << DT_HOURS_SHIFT);
-
- /*
- * If the number of days since 1970 is the same as
- * the last time we did the computation then skip
- * all this leap year and month stuff.
- */
- days = t / (24 * 60 * 60);
- if (days != lastday) {
- lastday = days;
- for (year = 1970; ; year++) {
- /*
- * XXX - works in 2000, but won't
- * work in 2100.
- */
- inc = year & 0x03 ? 365 : 366;
- if (days < inc)
- break;
- days -= inc;
- }
- /*
- * XXX - works in 2000, but won't work in 2100.
- */
- months = year & 0x03 ? regyear : leapyear;
- for (month = 0; days >= months[month]; month++)
- ;
- if (month > 0)
- days -= months[month - 1];
- lastddate = ((days + 1) << DD_DAY_SHIFT)
- + ((month + 1) << DD_MONTH_SHIFT);
- /*
- * Remember DOS's idea of time is relative
- * to 1980, but UN*X's is relative to 1970.
- * If somehow we get a time before 1980 then
- * don't give totally crazy results.
- */
- if (year > 1980)
- lastddate += (year - 1980) <<
- DD_YEAR_SHIFT;
- }
- }
- }
- if (dhp)
- *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
-
- *ddp = lastddate;
- *dtp = lastdtime;
-
- mutex_exit(&lastdt_lock);
-}
-
-/*
- * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
- * interval there were 8 regular years and 2 leap years.
- */
-#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
-
-static ushort_t lastdosdate;
-static ulong_t lastseconds;
-
-void
-smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
- struct timespec *tsp)
-{
- ulong_t seconds;
- ulong_t month;
- ulong_t year;
- ulong_t days;
- ushort_t *months;
-
- if (dd == 0) {
- tsp->tv_sec = 0;
- tsp->tv_nsec = 0;
- return;
- }
- seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
- + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
- + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
- + dh / 100;
-
- /*
- * If the year, month, and day from the last conversion are the
- * same then use the saved value.
- */
- mutex_enter(&lastdt_lock);
- if (lastdosdate != dd) {
- lastdosdate = (ushort_t)dd;
- days = 0;
- year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
- days = year * 365;
- days += year / 4 + 1; /* add in leap days */
- /*
- * XXX - works in 2000, but won't work in 2100.
- */
- if ((year & 0x03) == 0)
- days--; /* if year is a leap year */
- months = year & 0x03 ? regyear : leapyear;
- month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
- if (month < 1 || month > 12) {
- month = 1;
- }
- if (month > 1)
- days += months[month - 2];
- days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
- lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
- }
- smb_time_server2local(seconds + lastseconds, tzoff, tsp);
- tsp->tv_nsec = (dh % 100) * 10000000;
- mutex_exit(&lastdt_lock);
-}
-
-void
-smb_time_init(void)
-{
- mutex_init(&lastdt_lock, NULL, MUTEX_DEFAULT, NULL);
-}
-
-void
-smb_time_fini(void)
-{
- mutex_destroy(&lastdt_lock);
-}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
index f954056a79..1060139491 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRAN_H_
@@ -42,6 +44,9 @@
#include <sys/socket.h>
#include <sys/stream.h>
+#ifndef _KERNEL
+struct file;
+#endif
/*
* Known transports
@@ -49,11 +54,14 @@
#define SMBT_NBTCP 1
/*
- * Transport parameters
+ * Transport parameters, for tr_getparam/tr_setparam
*/
-#define SMBTP_SNDSZ 1 /* R - int */
-#define SMBTP_RCVSZ 2 /* R - int */
-#define SMBTP_TIMEOUT 3 /* RW - struct timespec */
+#define SMBTP_TCP_NODELAY 0x01 /* RW - int */
+#define SMBTP_TCP_CON_TMO 0x13 /* RW - int */
+#define SMBTP_KEEPALIVE SO_KEEPALIVE /* RW - int */
+#define SMBTP_SNDBUF SO_SNDBUF /* RW - int */
+#define SMBTP_RCVBUF SO_RCVBUF /* RW - int */
+#define SMBTP_RCVTIMEO SO_RCVTIMEO /* RW - int? */
struct smb_tran_ops;
@@ -62,12 +70,12 @@ struct smb_tran_desc {
int (*tr_create)(struct smb_vc *vcp, cred_t *cr);
int (*tr_done)(struct smb_vc *vcp);
int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap);
+ int (*tr_unbind)(struct smb_vc *vcp);
int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap);
int (*tr_disconnect)(struct smb_vc *vcp);
int (*tr_send)(struct smb_vc *vcp, mblk_t *m);
int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp);
int (*tr_poll)(struct smb_vc *vcp, int ticks);
- int (*tr_loan_fp)(struct smb_vc *, struct file *, cred_t *cr);
int (*tr_getparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_setparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_fatal)(struct smb_vc *vcp, int error);
@@ -78,12 +86,12 @@ typedef struct smb_tran_desc smb_tran_desc_t;
#define SMB_TRAN_CREATE(vcp, cr) (vcp)->vc_tdesc->tr_create(vcp, cr)
#define SMB_TRAN_DONE(vcp) (vcp)->vc_tdesc->tr_done(vcp)
#define SMB_TRAN_BIND(vcp, sap) (vcp)->vc_tdesc->tr_bind(vcp, sap)
+#define SMB_TRAN_UNBIND(vcp) (vcp)->vc_tdesc->tr_unbind(vcp)
#define SMB_TRAN_CONNECT(vcp, sap) (vcp)->vc_tdesc->tr_connect(vcp, sap)
#define SMB_TRAN_DISCONNECT(vcp) (vcp)->vc_tdesc->tr_disconnect(vcp)
#define SMB_TRAN_SEND(vcp, m) (vcp)->vc_tdesc->tr_send(vcp, m)
#define SMB_TRAN_RECV(vcp, m) (vcp)->vc_tdesc->tr_recv(vcp, m)
#define SMB_TRAN_POLL(vcp, t) (vcp)->vc_tdesc->tr_poll(vcp, t)
-#define SMB_TRAN_LOAN_FP(vcp, f, cr) (vcp)->vc_tdesc->tr_loan_fp(vcp, f, cr)
#define SMB_TRAN_GETPARAM(vcp, par, data) \
(vcp)->vc_tdesc->tr_getparam(vcp, par, data)
#define SMB_TRAN_SETPARAM(vcp, par, data) \
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
index 4f101a4f5f..849e91637e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -34,7 +34,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -73,13 +74,6 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-
static int nb_disconnect(struct nbpcb *nbp);
@@ -163,7 +157,7 @@ nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
case T_DISCON_IND:
/* Peer disconnected. */
NBDEBUG("T_DISCON_IND: reason=%d",
- pptr->discon_ind.DISCON_reason);
+ (int)pptr->discon_ind.DISCON_reason);
goto discon;
case T_ORDREL_IND:
/* Peer disconnecting. */
@@ -176,11 +170,11 @@ nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
goto discon;
default:
NBDEBUG("T_OK_ACK/prim=%d",
- pptr->ok_ack.CORRECT_prim);
+ (int)pptr->ok_ack.CORRECT_prim);
goto discon;
}
default:
- NBDEBUG("M_PROTO/type=%d", pptr->type);
+ NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
goto discon;
}
break; /* M_PROTO, M_PCPROTO */
@@ -485,22 +479,45 @@ out:
* This is called only by the thread creating this endpoint,
* so we're single-threaded here.
*/
-/*ARGSUSED*/
static int
smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
- struct nbpcb *nbp;
+ TIUSER *tiptr = NULL;
+ struct nbpcb *nbp = NULL;
+ dev_t dev;
+ int rc;
+ ushort_t fmode;
+
+ switch (vcp->vc_srvaddr.sa.sa_family) {
+ case AF_INET:
+ dev = nsmb_dev_tcp;
+ break;
+ case AF_INET6:
+ dev = nsmb_dev_tcp6;
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ fmode = FREAD|FWRITE;
+ rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
+ return (rc);
+ }
+ ASSERT(tiptr != NULL);
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
- nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+ nbp->nbp_state = NBST_IDLE;
nbp->nbp_vc = vcp;
- nbp->nbp_sndbuf = smb_tcpsndbuf;
- nbp->nbp_rcvbuf = smb_tcprcvbuf;
+ nbp->nbp_tiptr = tiptr;
+ nbp->nbp_fmode = fmode;
nbp->nbp_cred = cr;
crhold(cr);
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
+
vcp->vc_tdata = nbp;
return (0);
@@ -541,111 +558,74 @@ smb_nbst_done(struct smb_vc *vcp)
return (0);
}
-/*
- * Loan a transport file pointer (from user space) to this
- * IOD endpoint. There should be no other thread using this
- * endpoint when we do this, but lock for consistency.
- */
static int
-nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
- TIUSER *tiptr;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
int err;
- err = t_kopen(fp, 0, 0, &tiptr, cr);
- if (err != 0)
- return (err);
+ /* Only default bind supported. */
+ if (sap != NULL)
+ return (ENOTSUP);
- mutex_enter(&nbp->nbp_lock);
-
- nbp->nbp_tiptr = tiptr;
- nbp->nbp_fmode = tiptr->fp->f_flag;
- nbp->nbp_flags |= NBF_CONNECTED;
- nbp->nbp_state = NBST_SESSION;
-
- mutex_exit(&nbp->nbp_lock);
+ err = t_kbind(tiptr, NULL, NULL);
- return (0);
+ return (err);
}
-/*
- * Take back the transport file pointer we previously loaned.
- * It's possible there may be another thread in here, so let
- * others get out of the way before we pull the rug out.
- *
- * Some notes about the locking here: The higher-level IOD code
- * serializes activity such that at most one reader and writer
- * thread can be active in this code (and possibly both).
- * Keeping nbp_lock held during the activities of these two
- * threads would lead to the possibility of nbp_lock being
- * held by a blocked thread, so this instead sets one of the
- * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a
- * receiver is active (respectively). Lastly, tear-down is
- * the only tricky bit (here) where we must wait for any of
- * these activities to get out of current calls so they will
- * notice that we've turned off the NBF_CONNECTED flag.
- */
-static void
-nb_unloan_fp(struct nbpcb *nbp)
+static int
+smb_nbst_unbind(struct smb_vc *vcp)
{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
- mutex_enter(&nbp->nbp_lock);
-
- nbp->nbp_flags &= ~NBF_CONNECTED;
- while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) {
- nbp->nbp_flags |= NBF_LOCKWAIT;
- cv_wait(&nbp->nbp_cv, &nbp->nbp_lock);
- }
- if (nbp->nbp_frag != NULL) {
- freemsg(nbp->nbp_frag);
- nbp->nbp_frag = NULL;
- }
- if (nbp->nbp_tiptr != NULL) {
- (void) t_kclose(nbp->nbp_tiptr, 0);
- nbp->nbp_tiptr = NULL;
- }
- nbp->nbp_state = NBST_CLOSED;
+ err = t_kunbind(tiptr);
- mutex_exit(&nbp->nbp_lock);
+ return (err);
}
static int
-smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
{
- struct nbpcb *nbp = vcp->vc_tdata;
- int error = 0;
+ struct t_call call;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int alen, err;
+
+ /* Need the address length */
+ switch (sap->sa_family) {
+ case AF_INET:
+ alen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ alen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
- /*
- * Un-loan the existing one, if any.
- */
- (void) nb_disconnect(nbp);
- nb_unloan_fp(nbp);
+ /* sockaddr goes in the "addr" netbuf */
+ bzero(&call, sizeof (call));
+ call.addr.buf = (char *)sap;
+ call.addr.len = alen;
+ call.addr.maxlen = alen;
- /*
- * Loan the new one passed in.
- */
- if (fp != NULL) {
- error = nb_loan_fp(nbp, fp, cr);
- }
+ err = t_kconnect(tiptr, &call, NULL);
+ if (err != 0)
+ return (err);
- return (error);
-}
+ mutex_enter(&nbp->nbp_lock);
-/*ARGSUSED*/
-static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
-}
+ nbp->nbp_flags |= NBF_CONNECTED;
+ nbp->nbp_state = NBST_SESSION;
-/*ARGSUSED*/
-static int
-smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
+ mutex_exit(&nbp->nbp_lock);
+
+ return (0);
}
-/*ARGSUSED*/
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
@@ -832,42 +812,78 @@ smb_nbst_poll(struct smb_vc *vcp, int ticks)
return (ENOTSUP);
}
+/*ARGSUSED*/
static int
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
{
+ return (EINVAL);
+}
+
+static int
+smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+{
+ struct t_optmgmt oreq, ores;
+ struct {
+ struct T_opthdr oh;
+ int ival;
+ } opts;
struct nbpcb *nbp = vcp->vc_tdata;
+ int level, name, err;
switch (param) {
- case SMBTP_SNDSZ:
- *(int *)data = nbp->nbp_sndbuf;
+ case SMBTP_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ name = TCP_NODELAY;
break;
- case SMBTP_RCVSZ:
- *(int *)data = nbp->nbp_rcvbuf;
- break;
- case SMBTP_TIMEOUT:
- *(struct timespec *)data = nbp->nbp_timo;
- break;
-#ifdef SMBTP_SELECTID
- case SMBTP_SELECTID:
- *(void **)data = nbp->nbp_selectid;
+
+ case SMBTP_TCP_CON_TMO: /* int mSec */
+ level = IPPROTO_TCP;
+ name = TCP_CONN_ABORT_THRESHOLD;
break;
-#endif
-#ifdef SMBTP_UPCALL
- case SMBTP_UPCALL:
- *(void **)data = nbp->nbp_upcall;
+
+ case SMBTP_KEEPALIVE: // SO_KEEPALIVE
+ case SMBTP_SNDBUF: // SO_SNDBUF
+ case SMBTP_RCVBUF: // SO_RCVBUF
+ case SMBTP_RCVTIMEO: // SO_RCVTIMEO
+ level = SOL_SOCKET;
+ name = param;
break;
-#endif
+
default:
return (EINVAL);
}
- return (0);
-}
-/*ARGSUSED*/
-static int
-smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
-{
- return (EINVAL);
+ /* opt header */
+ opts.oh.len = sizeof (opts);
+ opts.oh.level = level;
+ opts.oh.name = name;
+ opts.oh.status = 0;
+ opts.ival = *(int *)data;
+
+ oreq.flags = T_NEGOTIATE;
+ oreq.opt.buf = (void *)&opts;
+ oreq.opt.len = sizeof (opts);
+ oreq.opt.maxlen = oreq.opt.len;
+
+ ores.flags = 0;
+ ores.opt.buf = NULL;
+ ores.opt.len = 0;
+ ores.opt.maxlen = 0;
+
+ err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
+ return (EPROTO);
+ }
+
+ if ((ores.flags & T_SUCCESS) == 0) {
+ cmn_err(CE_NOTE, "smb_nbst_setparam: "
+ "flags 0x%x, status 0x%x",
+ (int)ores.flags, (int)opts.oh.status);
+ return (EPROTO);
+ }
+
+ return (0);
}
/*
@@ -893,12 +909,12 @@ struct smb_tran_desc smb_tran_nbtcp_desc = {
smb_nbst_create,
smb_nbst_done,
smb_nbst_bind,
+ smb_nbst_unbind,
smb_nbst_connect,
smb_nbst_disconnect,
smb_nbst_send,
smb_nbst_recv,
smb_nbst_poll,
- smb_nbst_loan_fp,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
index f810a538cd..3c5e86639e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
@@ -32,13 +32,14 @@
* $Id: smb_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRANTCP_H_
#define _NETSMB_SMB_TRANTCP_H_
enum nbstate {
NBST_CLOSED,
+ NBST_IDLE,
NBST_RQSENT,
NBST_SESSION,
NBST_RETARGET,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
index fb587cd79e..d83c3a086c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -52,6 +53,7 @@
#include <netsmb/smb_osdep.h>
+#include <smb/winioctl.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_rq.h>
@@ -61,28 +63,6 @@
static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
/*
- * Ioctl function for SMBIOC_FLAGS2
- */
-int
-smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
-{
- struct smb_vc *vcp = NULL;
-
- /* This ioctl requires a session. */
- if ((vcp = sdp->sd_vc) == NULL)
- return (ENOTCONN);
-
- /*
- * Return the flags2 value.
- */
- if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
- sizeof (u_int16_t), flags))
- return (EFAULT);
-
- return (0);
-}
-
-/*
* Ioctl function for SMBIOC_GETSSNKEY
* Size copied out is SMBIOC_HASH_SZ.
*
@@ -105,7 +85,10 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
/*
* Return the session key.
*/
- if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
+ if (vcp->vc_ssnkey == NULL ||
+ vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
+ return (EINVAL);
+ if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
SMBIOC_HASH_SZ, flags))
return (EFAULT);
@@ -113,224 +96,90 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
}
/*
- * Ioctl function for SMBIOC_REQUEST
+ * Ioctl function for SMBIOC_XACTNP (transact named pipe)
*/
int
-smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
- smbioc_rq_t *ioc = NULL;
- struct smb_rq *rqp = NULL;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint32_t rsz;
+ struct smb_fh *fhp;
+ smbioc_xnp_t *ioc = NULL;
+ struct mbchain send_mb;
+ struct mdchain recv_md;
+ uint32_t rdlen;
int err, mbseg;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
-
- smb_credinit(&scred, cr);
- ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
- if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
- err = EFAULT;
- goto out;
- }
-
- /* See ddi_copyin, ddi_copyout */
- mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
-
- /*
- * Lots of SMB commands could be safe, but
- * these are the only ones used by libsmbfs.
- */
- switch (ioc->ioc_cmd) {
- /* These are OK */
- case SMB_COM_CLOSE:
- case SMB_COM_FLUSH:
- case SMB_COM_NT_CREATE_ANDX:
- case SMB_COM_OPEN_PRINT_FILE:
- case SMB_COM_CLOSE_PRINT_FILE:
- break;
-
- default:
- err = EPERM;
- goto out;
- }
-
- err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
- if (err)
- goto out;
-
- mbp = &rqp->sr_rq;
- err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
-
- err = smb_rq_simple(rqp);
- if (err == 0) {
- /*
- * This may have been an open, so save the
- * generation ID of the share, which we
- * check before trying read or write.
- */
- sdp->sd_vcgenid = ssp->ss_vcgenid;
-
- /*
- * Have reply data. to copyout.
- * SMB header already parsed.
- */
- mdp = &rqp->sr_rp;
- rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
- if (ioc->ioc_rbufsz < rsz) {
- err = EOVERFLOW;
- goto out;
- }
- ioc->ioc_rbufsz = rsz;
- err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
- if (err)
- goto out;
-
- }
-
- ioc->ioc_errclass = rqp->sr_errclass;
- ioc->ioc_serror = rqp->sr_serror;
- ioc->ioc_error = rqp->sr_error;
- (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
-
-out:
- if (rqp != NULL)
- smb_rq_done(rqp); /* free rqp */
- kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
-
- return (err);
-
-}
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
-/*
- * Ioctl function for SMBIOC_T2RQ
- */
-int
-smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
-{
- struct smb_cred scred;
- struct smb_share *ssp;
- smbioc_t2rq_t *ioc = NULL;
- struct smb_t2rq *t2p = NULL;
- struct mdchain *mdp;
- int err, len, mbseg;
+ /* After reconnect, force close+reopen */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_md, sizeof (recv_md));
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
goto out;
}
- /* See ddi_copyin, ddi_copyout */
+ /*
+ * Copyin the send data, into an mbchain,
+ * save output buffer size.
+ */
mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
-
- if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
- err = EINVAL;
+ err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
+ if (err)
goto out;
- }
+ rdlen = ioc->ioc_rdlen;
/*
- * Fill in the FID for libsmbfs transact named pipe.
+ * Run the SMB2 ioctl or SMB1 trans2
*/
- if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) {
- if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
- err = ESTALE;
- goto out;
- }
- ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
- }
-
- t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
- err = smb_t2_init(t2p, SSTOCP(ssp),
- ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
- if (err)
- goto out;
- t2p->t2_setupcount = ioc->ioc_setupcnt;
- t2p->t2_setupdata = ioc->ioc_setup;
-
- /* This ioc member is a fixed-size array. */
- if (ioc->ioc_name[0]) {
- /* Get the name length - carefully! */
- ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
- t2p->t_name_len = strlen(ioc->ioc_name);
- t2p->t_name = ioc->ioc_name;
+ smb_credinit(&scred, cr);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ioctl(ssp, &fhp->fh_fid2,
+ &send_mb, &recv_md, &rdlen,
+ FSCTL_PIPE_TRANSCEIVE, &scred);
+ } else {
+ err = smb_t2_xnp(ssp, fhp->fh_fid1,
+ &send_mb, &recv_md, &rdlen,
+ &ioc->ioc_more, &scred);
}
- t2p->t2_maxscount = 0;
- t2p->t2_maxpcount = ioc->ioc_rparamcnt;
- t2p->t2_maxdcount = ioc->ioc_rdatacnt;
-
- /* Transmit parameters */
- err = smb_cpdatain(&t2p->t2_tparam,
- ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
- if (err)
- goto out;
-
- /* Transmit data */
- err = smb_cpdatain(&t2p->t2_tdata,
- ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
- if (err)
- goto out;
-
- err = smb_t2_request(t2p);
-
- /* Copyout returned parameters. */
- mdp = &t2p->t2_rparam;
- if (err == 0 && mdp->md_top != NULL) {
- /* User's buffer large enough? */
- len = m_fixhdr(mdp->md_top);
- if (len > ioc->ioc_rparamcnt) {
- err = EMSGSIZE;
- goto out;
- }
- ioc->ioc_rparamcnt = (ushort_t)len;
- err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
- if (err)
- goto out;
- } else
- ioc->ioc_rparamcnt = 0;
+ smb_credrele(&scred);
/* Copyout returned data. */
- mdp = &t2p->t2_rdata;
- if (err == 0 && mdp->md_top != NULL) {
- /* User's buffer large enough? */
- len = m_fixhdr(mdp->md_top);
- if (len > ioc->ioc_rdatacnt) {
+ if (err == 0 && recv_md.md_top != NULL) {
+ /* User's buffer large enough for copyout? */
+ size_t len = m_fixhdr(recv_md.md_top);
+ if (len > ioc->ioc_rdlen) {
err = EMSGSIZE;
goto out;
}
- ioc->ioc_rdatacnt = (ushort_t)len;
- err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
+ err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);
if (err)
goto out;
} else
- ioc->ioc_rdatacnt = 0;
+ ioc->ioc_rdlen = 0;
- ioc->ioc_errclass = t2p->t2_sr_errclass;
- ioc->ioc_serror = t2p->t2_sr_serror;
- ioc->ioc_error = t2p->t2_sr_error;
- ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
+ /* Tell caller received length */
+ if (rdlen <= ioc->ioc_rdlen) {
+ /* Normal case */
+ ioc->ioc_rdlen = rdlen;
+ } else {
+ /* Buffer overlow. Leave ioc_rdlen */
+ ioc->ioc_more = 1;
+ }
(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
-
out:
- if (t2p != NULL) {
- /* Note: t2p->t_name no longer allocated */
- smb_t2_done(t2p);
- kmem_free(t2p, sizeof (*t2p));
- }
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
return (err);
}
@@ -358,22 +207,22 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
+ struct smb_fh *fhp;
smbioc_rw_t *ioc = NULL;
struct iovec aiov[1];
struct uio auio;
- uint16_t fh;
int err;
uio_rw_t rw;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
/* After reconnect, force close+reopen */
- if (sdp->sd_vcgenid != ssp->ss_vcgenid)
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
return (ESTALE);
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
@@ -392,15 +241,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
goto out;
}
- /*
- * If caller passes -1 in ioc_fh, then
- * use the FID from SMBIOC_NTCREATE.
- */
- if (ioc->ioc_fh == -1)
- fh = (uint16_t)sdp->sd_smbfid;
- else
- fh = (uint16_t)ioc->ioc_fh;
-
aiov[0].iov_base = ioc->ioc_base;
aiov[0].iov_len = (size_t)ioc->ioc_cnt;
@@ -412,7 +252,9 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
auio.uio_fmode = 0;
auio.uio_resid = (size_t)ioc->ioc_cnt;
- err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
+ smb_credinit(&scred, cr);
+ err = smb_rwuio(fhp, rw, &auio, &scred, 0);
+ smb_credrele(&scred);
/*
* On return ioc_cnt holds the
@@ -424,7 +266,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
out:
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
return (err);
}
@@ -439,20 +280,20 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
struct smb_cred scred;
struct mbchain name_mb;
struct smb_share *ssp;
+ struct smb_fh *fhp = NULL;
smbioc_ntcreate_t *ioc = NULL;
- uint16_t fid;
int err, nmlen;
+ mb_init(&name_mb);
+
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
return (ENOTCONN);
- /* Must not be already open. */
- if (sdp->sd_smbfid != -1)
+ /* Must not already have a file handle. */
+ if (sdp->sd_fh != NULL)
return (EINVAL);
- mb_init(&name_mb);
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
@@ -468,7 +309,14 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
if (err != 0)
goto out;
- /* Do the OtW open, save the FID. */
+ err = smb_fh_create(ssp, &fhp);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Do the OtW open, save the FID.
+ */
+ smb_credinit(&scred, cr);
err = smb_smb_ntcreate(ssp, &name_mb,
0, /* create flags */
ioc->ioc_req_acc,
@@ -478,18 +326,22 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
ioc->ioc_creat_opts,
NTCREATEX_IMPERSONATION_IMPERSONATION,
&scred,
- &fid,
+ fhp,
NULL,
NULL);
+ smb_credrele(&scred);
if (err != 0)
goto out;
- sdp->sd_smbfid = fid;
- sdp->sd_vcgenid = ssp->ss_vcgenid;
+ fhp->fh_rights = ioc->ioc_req_acc;
+ smb_fh_opened(fhp);
+ sdp->sd_fh = fhp;
+ fhp = NULL;
out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
mb_done(&name_mb);
return (err);
@@ -502,11 +354,17 @@ out:
int
smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
+ static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
struct smb_cred scred;
+ struct mbchain name_mb;
struct smb_share *ssp;
+ struct smb_fh *fhp = NULL;
smbioc_printjob_t *ioc = NULL;
- uint16_t fid;
- int err;
+ int err, cklen, nmlen;
+ uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
+ SA_RIGHT_FILE_READ_ATTRIBUTES;
+
+ mb_init(&name_mb);
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
@@ -516,8 +374,8 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
if (ssp->ss_type != STYPE_PRINTQ)
return (EINVAL);
- /* Must not be already open. */
- if (sdp->sd_smbfid != -1)
+ /* Must not already have a file handle. */
+ if (sdp->sd_fh != NULL)
return (EINVAL);
smb_credinit(&scred, cr);
@@ -526,21 +384,68 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
err = EFAULT;
goto out;
}
+
+ /*
+ * Use the print job title as the file name to open, but
+ * check for invalid characters first. See the notes in
+ * libsmbfs/smb/print.c about job name sanitizing.
+ */
ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
+ nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
+ cklen = strcspn(ioc->ioc_title, invalid_chars);
+ if (cklen < nmlen) {
+ err = EINVAL;
+ goto out;
+ }
- /* Do the OtW open, save the FID. */
- err = smb_smb_open_prjob(ssp, ioc->ioc_title,
- ioc->ioc_setuplen, ioc->ioc_prmode,
- &scred, &fid);
+ /* Build name_mb */
+ err = smb_put_dmem(&name_mb, SSTOVC(ssp),
+ ioc->ioc_title, nmlen,
+ SMB_CS_NONE, NULL);
if (err != 0)
goto out;
- sdp->sd_smbfid = fid;
- sdp->sd_vcgenid = ssp->ss_vcgenid;
+ err = smb_fh_create(ssp, &fhp);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Do the OtW open, save the FID.
+ */
+ smb_credinit(&scred, cr);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ntcreate(ssp, &name_mb,
+ NULL, NULL, /* cctx in, out */
+ 0, /* create flags */
+ access,
+ SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ &scred,
+ &fhp->fh_fid2,
+ NULL,
+ NULL);
+ } else {
+ err = smb_smb_open_prjob(ssp, ioc->ioc_title,
+ ioc->ioc_setuplen, ioc->ioc_prmode,
+ &scred, &fhp->fh_fid1);
+ }
+ smb_credrele(&scred);
+ if (err != 0)
+ goto out;
+
+ fhp->fh_rights = access;
+ smb_fh_opened(fhp);
+ sdp->sd_fh = fhp;
+ fhp = NULL;
out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
+ mb_done(&name_mb);
return (err);
}
@@ -549,31 +454,21 @@ out:
* Helper for nsmb_ioctl case
* SMBIOC_CLOSEFH
*/
+/*ARGSUSED*/
int
smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
{
- struct smb_cred scred;
- struct smb_share *ssp;
- uint16_t fid;
- int err;
+ struct smb_fh *fhp;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ sdp->sd_fh = NULL;
- if (sdp->sd_smbfid == -1)
- return (0);
- fid = (uint16_t)sdp->sd_smbfid;
- sdp->sd_smbfid = -1;
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
- smb_credinit(&scred, cr);
- if (ssp->ss_type == STYPE_PRINTQ)
- err = smb_smb_close_prjob(ssp, fid, &scred);
- else
- err = smb_smb_close(ssp, fid, NULL, &scred);
- smb_credrele(&scred);
-
- return (err);
+ return (0);
}
/*
@@ -825,24 +720,22 @@ smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
return (0);
}
-
/*
- * Ioctl function: SMBIOC_IOD_WORK
- *
- * Become the reader (IOD) thread, until either the connection is
- * reset by the server, or until the connection is idle longer than
- * some max time. (max idle time not yet implemented)
+ * Ioctl handler for all SMBIOC_IOD_...
*/
int
-smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
+ struct smb_vc *vcp;
int err = 0;
- /* Must have a valid session. */
+ /* Must be the IOD. */
+ if ((sdp->sd_flags & NSMBFL_IOD) == 0)
+ return (EINVAL);
+ /* Must have a VC and no share. */
if ((vcp = sdp->sd_vc) == NULL)
return (EINVAL);
- if (vcp->vc_flags & SMBV_GONE)
+ if (sdp->sd_share != NULL)
return (EINVAL);
/*
@@ -859,39 +752,53 @@ smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
return (err);
/*
- * Copy the "work" state, etc. into the VC
- * The MAC key is copied separately.
+ * Copy the "work" state, etc. into the VC,
+ * and back to the caller on the way out.
+ * Clear the "out only" part.
*/
if (ddi_copyin((void *)arg, &vcp->vc_work,
sizeof (smbioc_ssn_work_t), flags)) {
err = EFAULT;
goto out;
}
- if (vcp->vc_u_maclen) {
- vcp->vc_mackeylen = vcp->vc_u_maclen;
- vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
- if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
- vcp->vc_mackeylen, flags)) {
- err = EFAULT;
- goto out;
- }
- }
+ vcp->vc_work.wk_out_state = 0;
- err = smb_iod_vc_work(vcp, cr);
+ switch (cmd) {
- /* Caller wants state here. */
- vcp->vc_work.wk_out_state = vcp->vc_state;
+ case SMBIOC_IOD_CONNECT:
+ err = nsmb_iod_connect(vcp, cr);
+ break;
- (void) ddi_copyout(&vcp->vc_work, (void *)arg,
- sizeof (smbioc_ssn_work_t), flags);
+ case SMBIOC_IOD_NEGOTIATE:
+ err = nsmb_iod_negotiate(vcp, cr);
+ break;
-out:
- if (vcp->vc_mackey) {
- kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- vcp->vc_mackey = NULL;
- vcp->vc_mackeylen = 0;
+ case SMBIOC_IOD_SSNSETUP:
+ err = nsmb_iod_ssnsetup(vcp, cr);
+ break;
+
+ case SMBIOC_IOD_WORK:
+ err = smb_iod_vc_work(vcp, flags, cr);
+ break;
+
+ case SMBIOC_IOD_IDLE:
+ err = smb_iod_vc_idle(vcp);
+ break;
+
+ case SMBIOC_IOD_RCFAIL:
+ err = smb_iod_vc_rcfail(vcp);
+ break;
+
+ default:
+ err = ENOTTY;
+ break;
}
+out:
+ vcp->vc_work.wk_out_state = vcp->vc_state;
+ (void) ddi_copyout(&vcp->vc_work, (void *)arg,
+ sizeof (smbioc_ssn_work_t), flags);
+
/*
* The IOD thread is leaving the driver. Clear iod_thr,
* and wake up anybody waiting for us to quit.
@@ -904,67 +811,104 @@ out:
return (err);
}
-/*
- * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
- *
- * Wait for user-level requests to be enqueued on this session,
- * and then return to the user-space helper, which will then
- * initiate a reconnect, etc.
- */
int
-smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
+smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
- int err = 0;
-
- /* Must have a valid session. */
- if ((vcp = sdp->sd_vc) == NULL)
- return (EINVAL);
- if (vcp->vc_flags & SMBV_GONE)
- return (EINVAL);
+ int err;
/*
- * Is there already an IOD for this VC?
- * (Should never happen.)
+ * Serialize ioctl calls. The smb_usr_... functions
+ * don't expect concurrent calls on a given sdp.
*/
- SMB_VC_LOCK(vcp);
- if (vcp->iod_thr == NULL)
- vcp->iod_thr = curthread;
- else
- err = EEXIST;
- SMB_VC_UNLOCK(vcp);
- if (err)
- return (err);
-
- /* nothing to copyin */
+ mutex_enter(&sdp->sd_lock);
+ if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
+ mutex_exit(&sdp->sd_lock);
+ return (EBUSY);
+ }
+ sdp->sd_flags |= NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
+ err = 0;
switch (cmd) {
- case SMBIOC_IOD_IDLE:
- err = smb_iod_vc_idle(vcp);
+ case SMBIOC_GETVERS:
+ (void) ddi_copyout(&nsmb_version, (void *)arg,
+ sizeof (nsmb_version), flags);
+ break;
+
+ case SMBIOC_GETSSNKEY:
+ err = smb_usr_get_ssnkey(sdp, arg, flags);
+ break;
+
+ case SMBIOC_DUP_DEV:
+ err = smb_usr_dup_dev(sdp, arg, flags);
+ break;
+
+ case SMBIOC_XACTNP:
+ err = smb_usr_xnp(sdp, arg, flags, cr);
break;
+ case SMBIOC_READ:
+ case SMBIOC_WRITE:
+ err = smb_usr_rw(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_NTCREATE:
+ err = smb_usr_ntcreate(sdp, arg, flags, cr);
+ break;
+
+ case SMBIOC_PRINTJOB:
+ err = smb_usr_printjob(sdp, arg, flags, cr);
+ break;
+
+ case SMBIOC_CLOSEFH:
+ err = smb_usr_closefh(sdp, cr);
+ break;
+
+ case SMBIOC_SSN_CREATE:
+ case SMBIOC_SSN_FIND:
+ err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_SSN_KILL:
+ case SMBIOC_SSN_RELE:
+ err = smb_usr_drop_ssn(sdp, cmd);
+ break;
+
+ case SMBIOC_TREE_CONNECT:
+ case SMBIOC_TREE_FIND:
+ err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_TREE_KILL:
+ case SMBIOC_TREE_RELE:
+ err = smb_usr_drop_tree(sdp, cmd);
+ break;
+
+ case SMBIOC_IOD_CONNECT:
+ case SMBIOC_IOD_NEGOTIATE:
+ case SMBIOC_IOD_SSNSETUP:
+ case SMBIOC_IOD_WORK:
+ case SMBIOC_IOD_IDLE:
case SMBIOC_IOD_RCFAIL:
- err = smb_iod_vc_rcfail(vcp);
+ err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_PK_ADD:
+ case SMBIOC_PK_DEL:
+ case SMBIOC_PK_CHK:
+ case SMBIOC_PK_DEL_OWNER:
+ case SMBIOC_PK_DEL_EVERYONE:
+ err = smb_pkey_ioctl(cmd, arg, flags, cr);
break;
default:
err = ENOTTY;
- goto out;
+ break;
}
- /* Both of these ioctls copy out the new state. */
- (void) ddi_copyout(&vcp->vc_state, (void *)arg,
- sizeof (int), flags);
-
-out:
- /*
- * The IOD thread is leaving the driver. Clear iod_thr,
- * and wake up anybody waiting for us to quit.
- */
- SMB_VC_LOCK(vcp);
- vcp->iod_thr = NULL;
- cv_broadcast(&vcp->vc_statechg);
- SMB_VC_UNLOCK(vcp);
+ mutex_enter(&sdp->sd_lock);
+ sdp->sd_flags &= ~NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
index 47b2783c58..b7f6bd8570 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -63,9 +64,9 @@
* m_data ... (m_data + m_len)
* In Unix STREAMS, the mblk payload is:
* b_rptr ... b_wptr
- *
+ *
* Here are some handy conversion notes:
- *
+ *
* struct mbuf struct mblk
* m->m_next m->b_cont
* m->m_nextpkt m->b_next
@@ -75,7 +76,7 @@
* &m->m_dat[MLEN] m->b_datap->db_lim
* M_TRAILINGSPACE(m) MBLKTAIL(m)
* m_freem(m) freemsg(m)
- *
+ *
* Note that mbufs chains also have a special "packet" header,
* which has the length of the whole message. In STREAMS one
* typically just calls msgdsize(m) to get that.
@@ -113,6 +114,9 @@
*/
#define MLEN 4096
+#if (MLEN < SMB2_HDRLEN)
+#error "MLEN can't fit a contiguous SMB2 header"
+#endif
/*
* Some UIO routines.
@@ -420,6 +424,22 @@ mb_put_padbyte(struct mbchain *mbp)
return (0);
}
+/*
+ * Adds padding to 8 byte boundary
+ */
+int
+mb_put_align8(struct mbchain *mbp)
+{
+ static const char zeros[8] = { 0 };
+ int pad_len = 0;
+
+ if ((mbp->mb_count % 8) != 0) {
+ pad_len = 8 - (mbp->mb_count % 8);
+ MB_PUT_INLINE(mbp, zeros, pad_len);
+ }
+ return (0);
+}
+
int
mb_put_uint8(struct mbchain *mbp, u_int8_t x)
{
@@ -537,6 +557,7 @@ mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
/*
* Append an mblk to the chain.
+ * Note: The mblk_t *m is consumed.
*/
int
mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
@@ -576,6 +597,29 @@ mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
}
/*
+ * Put an mbchain into another mbchain
+ * Leave sub_mbp untouched.
+ */
+int
+mb_put_mbchain(struct mbchain *mbp, struct mbchain *sub_mbp)
+{
+ mblk_t *m;
+
+ if (sub_mbp == NULL)
+ return (0);
+
+ m = sub_mbp->mb_top;
+ if (m == NULL)
+ return (0);
+
+ m = dupmsg(m);
+ if (m == NULL)
+ return (ENOSR);
+
+ return (mb_put_mbuf(mbp, m));
+}
+
+/*
* copies a uio scatter/gather list to an mbuf chain.
*/
int
@@ -875,6 +919,7 @@ md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
/*
* Get the next SIZE bytes as a separate mblk.
+ * Advances position in mdp by SIZE.
*/
int
md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
@@ -898,6 +943,7 @@ md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
rm = m_copym(m, off, size, M_WAITOK);
if (rm == NULL)
return (EBADRPC);
+ (void) md_get_mem(mdp, NULL, size, MB_MSYSTEM);
*ret = rm;
return (0);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
index c5af3391c6..1e16e95d18 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -69,12 +71,12 @@ static int
smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
{
struct smb_cred scred;
- int error, cerror;
smbmntinfo_t *smi;
smbnode_t *np;
- u_int16_t fid = SMB_FID_UNUSED;
+ smb_fh_t *fid = NULL;
uint32_t sdlen = SMALL_SD_SIZE;
uint32_t rights = STD_RIGHT_READ_CONTROL_ACCESS;
+ int error;
if (selector & SACL_SECURITY_INFORMATION)
rights |= SEC_RIGHT_SYSTEM_SECURITY;
@@ -82,9 +84,6 @@ smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
np = VTOSMB(vp);
smi = VTOSMI(vp);
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
@@ -95,8 +94,8 @@ again:
/*
* This does the OTW Get
*/
- error = smbfs_smb_getsec_m(smi->smi_share, fid,
- &scred, selector, mp, &sdlen);
+ error = smbfs_smb_getsec(smi->smi_share, fid,
+ selector, mp, &sdlen, &scred);
/*
* Server may give us an error indicating that we
* need a larger data buffer to receive the SD,
@@ -115,14 +114,10 @@ again:
sdlen <= MAX_RAW_SD_SIZE)
goto again;
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing file %s\n",
- cerror, np->n_rpath);
+ smbfs_smb_tmpclose(np, fid);
out:
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
return (error);
}
@@ -139,11 +134,11 @@ static int
smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
{
struct smb_cred scred;
- int error, cerror;
smbmntinfo_t *smi;
smbnode_t *np;
uint32_t rights;
- u_int16_t fid = SMB_FID_UNUSED;
+ smb_fh_t *fid = NULL;
+ int error;
np = VTOSMB(vp);
smi = VTOSMI(vp);
@@ -164,9 +159,6 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
if (selector & SACL_SECURITY_INFORMATION)
rights |= SEC_RIGHT_SYSTEM_SECURITY;
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
@@ -185,17 +177,13 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
/*
* This does the OTW Set
*/
- error = smbfs_smb_setsec_m(smi->smi_share, fid,
- &scred, selector, mp);
+ error = smbfs_smb_setsec(smi->smi_share, fid,
+ selector, mp, &scred);
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing file %s\n",
- cerror, np->n_rpath);
+ smbfs_smb_tmpclose(np, fid);
out:
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
return (error);
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
index 44319e6682..41a6f41a2b 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
@@ -24,6 +24,8 @@
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -60,6 +62,7 @@
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
+#ifdef _KERNEL
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/page.h>
@@ -67,6 +70,7 @@
#include <vm/seg.h>
#include <vm/seg_map.h>
#include <vm/seg_vn.h>
+#endif // _KERNEL
#define ATTRCACHE_VALID(vp) (gethrtime() < VTOSMB(vp)->r_attrtime)
@@ -394,11 +398,23 @@ smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap)
static int
smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
{
- struct smbnode *np;
struct smb_cred scred;
+ smbnode_t *np = VTOSMB(vp);
+ smb_share_t *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp = NULL;
int error;
- np = VTOSMB(vp);
+ bzero(fap, sizeof (*fap));
+
+ /*
+ * Special case the XATTR directory here (all fake).
+ * OK to leave a,c,m times zero (expected).
+ */
+ if (vp->v_flag & V_XATTRDIR) {
+ fap->fa_attr = SMB_FA_DIR;
+ fap->fa_size = DEV_BSIZE;
+ return (0);
+ }
/*
* Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
@@ -412,8 +428,28 @@ smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
return (EINTR);
smb_credinit(&scred, cr);
- bzero(fap, sizeof (*fap));
- error = smbfs_smb_getfattr(np, fap, &scred);
+// Does the attr. open code path work for streams?
+// Trying that, and if it doesn't work enable this.
+#if 0 // XXX
+ /*
+ * Extended attribute files
+ */
+ if (np->n_flag & N_XATTR) {
+ error = smbfs_xa_getfattr(np, fap, scrp);
+ goto out;
+ }
+#endif // XXX
+
+ if (np->n_fidrefs > 0 &&
+ (fhp = np->n_fid) != NULL &&
+ (fhp->fh_vcgenid == ssp->ss_vcgenid)) {
+ /* Use the FID we have. */
+ error = smbfs_smb_getfattr(np, fhp, fap, &scred);
+
+ } else {
+ /* This will do an attr open */
+ error = smbfs_smb_getpattr(np, fap, &scred);
+ }
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -816,9 +852,8 @@ static void smbfs_cb_nop(smb_share_t *ss)
smb_fscb_t smbfs_cb = {
.fscb_disconn = smbfs_dead,
- .fscb_connect = smbfs_cb_nop,
- .fscb_down = smbfs_cb_nop,
- .fscb_up = smbfs_cb_nop };
+ .fscb_connect = smbfs_cb_nop
+};
#endif /* NEED_SMBFS_CALLBACKS */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
index 5bbbae860e..163a5a4504 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
@@ -35,11 +35,14 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cred.h>
+#include <sys/errno.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
index 2fe7476814..62d47e9b20 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _FS_SMBFS_NODE_H_
@@ -221,10 +222,8 @@ typedef struct smbnode {
struct smbfs_fctx *n_dirseq; /* ff context */
int n_dirofs; /* last ff offset */
int n_fidrefs;
- uint16_t n_fid; /* file handle */
+ smb_fh_t *n_fid; /* file handle */
enum vtype n_ovtype; /* vnode type opened */
- uint32_t n_rights; /* granted rights */
- int n_vcgenid; /* gereration no. (reconnect) */
/*
* Misc. bookkeeping
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
index db920f21b8..9a44867521 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
@@ -28,18 +28,18 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/inttypes.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sunddi.h>
@@ -48,6 +48,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -62,375 +63,70 @@
*/
const uint64_t NT1980 = 11960035200ULL*10000000ULL;
-/*
- * Local functions.
- * Not static, to aid debugging.
- */
-
-int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp);
-int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel);
-
-int smbfs_smb_statfsLM1(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-int smbfs_smb_statfsLM2(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-
-int smbfs_smb_setfattrNT(struct smbnode *np, int fid,
- uint32_t attr, struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
-int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
- struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
-int smbfs_smb_setpattr1(struct smbnode *np,
- const char *name, int len, uint32_t attr,
- struct timespec *mtime, struct smb_cred *scrp);
-
-
-/*
- * Todo: locking over-the-wire
- */
-#ifdef APPLE
-
-static int
-smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- uint8_t ltype = 0;
- int error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
-
- if (op == SMB_LOCK_SHARED)
- ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
- /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
- if (largelock)
- ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint8(mbp, 0xff); /* secondary command */
- mb_put_uint8(mbp, 0); /* MBZ */
- mb_put_uint16le(mbp, 0);
- mb_put_uint16le(mbp, np->n_fid);
- mb_put_uint8(mbp, ltype); /* locktype */
- mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
- mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
- mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
- mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint16le(mbp, pid);
- if (!largelock) {
- mb_put_uint32le(mbp, start);
- mb_put_uint32le(mbp, len);
- } else {
- mb_put_uint16le(mbp, 0); /* pad */
- mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
- mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
- mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
- mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
- }
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * unlock send or lock response, or we could
- * lose track of an outstanding lock.
- */
- if (op == SMB_LOCK_RELEASE)
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- else
- rqp->sr_flags |= SMBR_NOINTR_RECV;
-
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
-
- if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
- /*
- * TODO: use LOCK_BYTE_RANGE here.
- */
- return (EINVAL);
-
- /*
- * XXX: compute largelock via:
- * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
- */
- return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
- largelock, scrp, timeout));
-}
-
-#endif /* APPLE */
/*
- * Helper for smbfs_getattr
- * Something like nfs_getattr_otw
+ * Helper for smbfs_getattr_otw
+ * used when we have an open FID
*/
int
smbfs_smb_getfattr(
struct smbnode *np,
+ smb_fh_t *fhp,
struct smbfattr *fap,
struct smb_cred *scrp)
{
+ struct smb_share *ssp = np->n_mount->smi_share;
int error;
- /*
- * This lock is necessary for FID-based calls.
- * Lock may be writer (via open) or reader.
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * Extended attribute directory or file.
- */
- if (np->n_flag & N_XATTR) {
- error = smbfs_xa_getfattr(np, fap, scrp);
- return (error);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp);
+ } else {
+ error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp);
}
- error = smbfs_smb_trans2_query(np, fap, scrp, 0);
- if (error != EINVAL)
- return (error);
-
- /* fallback */
- error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
-
return (error);
}
/*
- * Common function for QueryFileInfo, QueryPathInfo.
+ * Helper for smbfs_getattr_otw
+ * used when we don't have an open FID
+ *
+ * For SMB1 we can just use the path form of trans2 query.
+ * For SMB2 we need to do an attribute-only open.
+ * See smbfs_smb2_getpattr()
*/
int
-smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel)
+smbfs_smb_getpattr(
+ struct smbnode *np,
+ struct smbfattr *fap,
+ struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct smb_t2rq *t2p;
- int error, svtz, timesok = 1;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t cmd, date, time, wattr;
- uint64_t llongint, lsize;
- uint32_t size, dattr;
-
- /*
- * Shared lock for n_fid use below.
- * See smbfs_smb_getfattr()
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * If we have a valid open FID, use it.
- */
- if ((np->n_fidrefs > 0) &&
- (np->n_fid != SMB_FID_UNUSED) &&
- (np->n_vcgenid == ssp->ss_vcgenid))
- cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
- else
- cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
-
-top:
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- if (!infolevel) {
- if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
- infolevel = SMB_QFILEINFO_STANDARD;
- else
- infolevel = SMB_QFILEINFO_ALL_INFO;
- }
-
- if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
- mb_put_uint16le(mbp, np->n_fid);
-
- mb_put_uint16le(mbp, infolevel);
-
- if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
- mb_put_uint32le(mbp, 0);
- /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error) {
- smb_t2_done(t2p);
- return (error);
- }
- }
+ int error;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = vcp->vc_txmax;
- error = smb_t2_request(t2p);
- if (error) {
- smb_t2_done(t2p);
- /* Invalid info level? Try fallback. */
- if (error == EINVAL &&
- infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- return (error);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_getpattr(np, fap, scrp);
+ } else {
+ uint16_t fid = SMB_FID_UNUSED;
+ error = smbfs_smb1_trans2_query(np, fid, fap, scrp);
}
- mdp = &t2p->t2_rdata;
- svtz = vcp->vc_sopt.sv_tz;
- switch (infolevel) {
- case SMB_QFILEINFO_STANDARD:
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
- md_get_uint32le(mdp, &size); /* EOF position */
- fap->fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- fap->fa_allocsz = size;
- error = md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- timesok = 1;
- break;
- case SMB_QFILEINFO_ALL_INFO:
- timesok = 0;
- /* creation time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_createtime);
-
- /* last access time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_atime);
-
- /* last write time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_mtime);
-
- /* last change time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_ctime);
-
- /* attributes */
- md_get_uint32le(mdp, &dattr);
- fap->fa_attr = dattr;
- /*
- * 4-Byte alignment - discard
- * Specs don't talk about this.
- */
- md_get_uint32le(mdp, NULL);
- /* allocation size */
- md_get_uint64le(mdp, &lsize);
- fap->fa_allocsz = lsize;
- /* File size */
- error = md_get_uint64le(mdp, &lsize);
- fap->fa_size = lsize;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", infolevel);
- error = EINVAL;
- }
- smb_t2_done(t2p);
- /*
- * if all times are zero (observed with FAT on NT4SP6)
- * then fall back to older info level
- */
- if (!timesok) {
- if (infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- error = EINVAL;
- }
return (error);
}
/*
- * Support functions for _qstreaminfo
- * Moved to smbfs_xattr.c
+ * Get and parse FileFsAttributeInformation
*/
-
int
smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
struct smb_cred *scrp)
{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
int error;
- uint32_t nlen;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
- t2p->t2_maxpcount = 4;
- t2p->t2_maxdcount = 4 * 3 + 512;
- error = smb_t2_request(t2p);
- if (error)
- goto out;
-
- mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, &fsa->fsa_aflags);
- md_get_uint32le(mdp, &fsa->fsa_maxname);
- error = md_get_uint32le(mdp, &nlen); /* fs name length */
- if (error)
- goto out;
- /*
- * Get the FS type name.
- */
- bzero(fsa->fsa_tname, FSTYPSZ);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- uint16_t tmpbuf[FSTYPSZ];
- size_t tmplen, outlen;
-
- if (nlen > sizeof (tmpbuf))
- nlen = sizeof (tmpbuf);
- error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
- tmplen = nlen / 2; /* UCS-2 chars */
- outlen = FSTYPSZ - 1;
- (void) uconv_u16tou8(tmpbuf, &tmplen,
- (uchar_t *)fsa->fsa_tname, &outlen,
- UCONV_IN_LITTLE_ENDIAN);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_qfsattr(ssp, fsa, scrp);
} else {
- if (nlen > (FSTYPSZ - 1))
- nlen = FSTYPSZ - 1;
- error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
+ error = smbfs_smb1_qfsattr(ssp, fsa, scrp);
}
/*
@@ -442,652 +138,113 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
SMB_SS_UNLOCK(ssp);
}
-out:
- smb_t2_done(t2p);
- return (0);
+ return (error);
}
int
smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scp)
{
- int error;
-
- if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
- error = smbfs_smb_statfsLM2(ssp, sbp, scp);
- else
- error = smbfs_smb_statfsLM1(ssp, sbp, scp);
-
- return (error);
-}
-
-int
-smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t bsize;
- uint32_t units, bpu, funits;
- uint64_t s, t, f;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
- t2p->t2_maxpcount = 4;
- t2p->t2_maxdcount = 4 * 4 + 2;
- error = smb_t2_request(t2p);
- if (error)
- goto out;
-
- mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, NULL); /* fs id */
- md_get_uint32le(mdp, &bpu);
- md_get_uint32le(mdp, &units);
- md_get_uint32le(mdp, &funits);
- error = md_get_uint16le(mdp, &bsize);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
- sbp->f_files = (-1); /* total file nodes in file system */
- sbp->f_ffree = (-1); /* free file nodes in fs */
-
-out:
- smb_t2_done(t2p);
- return (0);
-}
-
-int
-smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct mdchain *mdp;
- uint16_t units, bpu, bsize, funits;
- uint64_t s, t, f;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
- scrp);
- if (error)
- return (error);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
-
- smb_rq_getreply(rqp, &mdp);
- md_get_uint16le(mdp, &units);
- md_get_uint16le(mdp, &bpu);
- md_get_uint16le(mdp, &bsize);
- error = md_get_uint16le(mdp, &funits);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
- sbp->f_files = (-1); /* total file nodes in file system */
- sbp->f_ffree = (-1); /* free file nodes in fs */
-
-out:
- smb_rq_done(rqp);
- return (0);
-}
-
-int
-smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint64le(mbp, newsize);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
-}
-
-int
-smbfs_smb_setdisp(struct smbnode *np,
- uint16_t fid, uint8_t newdisp,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint8(mbp, newdisp);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
-}
-
-/*
- * On SMB1, the trans2 rename only allows a rename where the
- * source and target are in the same directory. If you give
- * the server any separators, you get "status not supported".
- */
-
-/*ARGSUSED*/
-int
-smbfs_smb_t2rename(struct smbnode *np,
- const char *tname, int tnlen, struct smb_cred *scrp,
- uint16_t fid, int overwrite)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_fs_size_info info;
struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int32_t *ucslenp;
+ uint32_t bps, spu;
int error;
- if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
- return (ENOTSUP);
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_statfs(ssp, &info, scp);
+ } else {
+ error = smbfs_smb1_statfs(ssp, &info, scp);
+ }
if (error)
return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
- mb_put_uint16le(mbp, 0); /* reserved, nowadays */
-
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint32le(mbp, overwrite); /* one or zero */
- mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ /* A bit of paranoia. */
+ bps = info.bytes_per_sect;
+ if (bps < DEV_BSIZE)
+ bps = DEV_BSIZE;
+ spu = info.sect_per_unit;
+ if (spu == 0)
+ spu = 1;
- ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
- mbp->mb_count = 0;
- error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
- if (error)
- goto out;
- *ucslenp = htolel(mbp->mb_count);
+ /* preferred file system block size */
+ sbp->f_bsize = bps * spu;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
- return (error);
-}
+ /* file system block size ("fragment size") */
+ sbp->f_frsize = bps;
-int
-smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
+ /* total blocks of f_frsize */
+ sbp->f_blocks = info.total_units * spu;
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ /* free blocks of f_frsize */
+ sbp->f_bfree = info.actual_avail * spu;
- if (!(np->n_flag & NFLUSHWIRE))
- return (0);
- if (np->n_fidrefs == 0)
- return (0); /* not open */
+ /* free blocks avail to non-superuser */
+ sbp->f_bavail = info.caller_avail * spu;
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
+ sbp->f_files = (-1); /* total file nodes in file system */
+ sbp->f_ffree = (-1); /* free file nodes in fs */
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, np->n_fid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- if (!error) {
- mutex_enter(&np->r_statelock);
- np->n_flag &= ~NFLUSHWIRE;
- mutex_exit(&np->r_statelock);
- }
return (error);
}
int
-smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
+smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp,
+ uint8_t disp, struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
+ int err;
- if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- /*
- * This call knows about 64-bit offsets.
- */
- error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
- if (!error) {
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (0);
- }
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp);
+ } else {
+ err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp);
}
- /*
- * OK, so fallback to SMB_COM_WRITE, but note:
- * it only supports 32-bit file offsets.
- */
- if (newsize > UINT32_MAX)
- return (EFBIG);
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0);
- mb_put_uint32le(mbp, newsize);
- mb_put_uint16le(mbp, 0);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (error);
+ return (err);
}
-/*
- * Old method for getting file attributes.
- */
int
-smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp)
+smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp,
+ uint64_t size, struct smb_cred *scrp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc;
int error;
- uint16_t wattr;
- uint32_t longint;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
- name, nmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 10) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint,
- SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
- error = md_get_uint32le(mdp, &longint);
- fap->fa_size = longint;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-/*
- * Set DOS file attributes. mtime should be NULL for dialects above lm10
- */
-int
-smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
- uint32_t attr, struct timespec *mtime,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- long time;
- int error, svtz;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
- if (error)
- return (error);
- svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, (uint16_t)attr);
- if (mtime) {
- smb_time_local2server(mtime, svtz, &time);
- } else
- time = 0;
- mb_put_uint32le(mbp, time); /* mtime */
- mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp);
+ } else {
+ error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp);
}
- mb_put_uint8(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smbfattr fa;
- int error;
- uint32_t attr;
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && !(attr & SMB_FA_HIDDEN)) {
- attr |= SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
return (error);
}
-int
-smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smbfattr fa;
- uint32_t attr;
- int error;
-
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && (attr & SMB_FA_HIDDEN)) {
- attr &= ~SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
- return (error);
-}
-
/*
* Set file attributes (optionally: DOS attr, atime, mtime)
- * either by open FID or by path name (FID == -1).
+ * Always have an open FID with set attr rights.
*/
int
smbfs_smb_setfattr(
- struct smbnode *np,
- int fid,
+ struct smb_share *ssp,
+ smb_fh_t *fhp,
uint32_t attr,
struct timespec *mtime,
struct timespec *atime,
struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
+ struct mbchain mb_info;
+ struct mbchain *mbp = &mb_info;
+ uint64_t tm;
int error;
/*
- * Normally can use the trans2 call.
- */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_setfattrNT(np, fid,
- attr, mtime, atime, scrp);
- return (error);
- }
-
- /*
- * Fall-back for older protocols.
+ * Build a struct FILE_BASIC_INFORMATION in mbp
+ * LARGE_INTEGER CreationTime;
+ * LARGE_INTEGER LastAccessTime;
+ * LARGE_INTEGER LastWriteTime;
+ * LARGE_INTEGER ChangeTime;
+ * ULONG FileAttributes;
+ * Zero in times means "no change".
*/
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
- error = smbfs_smb_setftime1(np, fid,
- mtime, atime, scrp);
- return (error);
- }
- error = smbfs_smb_setpattr1(np, NULL, 0,
- attr, mtime, scrp);
- return (error);
-}
-
-/*
- * Set file atime and mtime. Isn't supported by core dialect.
- */
-int
-smbfs_smb_setftime1(
- struct smbnode *np,
- uint16_t fid,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- uint16_t date, time;
- int error, tzoff;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
- if (error)
- return (error);
-
- tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint32le(mbp, 0); /* creation time */
-
- if (atime)
- smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- if (mtime)
- smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- SMBVDEBUG("%d\n", error);
- smb_rq_done(rqp);
- return (error);
-}
-
-/*
- * Set DOS file attributes, either via open FID or by path name.
- * Looks like this call can be used only if CAP_NT_SMBS bit is on.
- *
- * When setting via path (fid == -1):
- * *BASIC_INFO works with Samba, but Win2K servers say it is an
- * invalid information level on a SET_PATH_INFO. Note Win2K does
- * support *BASIC_INFO on a SET_FILE_INFO, and they support the
- * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
- */
-int
-smbfs_smb_setfattrNT(
- struct smbnode *np,
- int fid, /* if fid == -1, set by path */
- uint32_t attr,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- uint64_t tm;
- int error;
- uint16_t cmd, level;
-
- if (fid == -1) {
- cmd = SMB_TRANS2_SET_PATH_INFORMATION;
- } else {
- if (fid > UINT16_MAX)
- return (EINVAL);
- cmd = SMB_TRANS2_SET_FILE_INFORMATION;
- }
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- level = SMB_SFILEINFO_BASIC_INFORMATION;
- else
- level = SMB_SFILEINFO_BASIC_INFO;
-
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
-
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
-
- if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
- mb_put_uint16le(mbp, fid);
-
- mb_put_uint16le(mbp, level);
- mb_put_uint32le(mbp, 0); /* MBZ */
-
- if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error != 0)
- goto out;
- }
-
- /* FAT file systems don't support dates earlier than 1980. */
-
- mbp = &t2p->t2_tdata;
mb_init(mbp);
mb_put_uint64le(mbp, 0); /* creation time */
if (atime) {
@@ -1097,7 +254,7 @@ smbfs_smb_setfattrNT(
tm = NT1980;
} else
tm = 0;
- mb_put_uint64le(mbp, tm); /* access time */
+ mb_put_uint64le(mbp, tm); /* last access time */
if (mtime) {
smb_time_local2NT(mtime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
@@ -1106,19 +263,35 @@ smbfs_smb_setfattrNT(
} else
tm = 0;
mb_put_uint64le(mbp, tm); /* last write time */
- mb_put_uint64le(mbp, 0); /* ctime (no change) */
+ mb_put_uint64le(mbp, 0); /* change time */
mb_put_uint32le(mbp, attr);
- mb_put_uint32le(mbp, 0); /* padding */
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp);
+ } else {
+ error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp);
+ }
+
+ return (error);
+}
+
+int
+smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+{
+ int error;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp);
+ }
return (error);
}
/*
* Modern create/open of file or directory.
+ * On success, fills in fhp->fh_fid* and fhp->fh_rights
*/
int
smbfs_smb_ntcreatex(
@@ -1132,7 +305,7 @@ smbfs_smb_ntcreatex(
uint32_t disp, /* open disposition */
uint32_t createopt, /* NTCREATEX_OPTIONS_ */
struct smb_cred *scrp,
- uint16_t *fidp, /* returned FID */
+ smb_fh_t *fhp, /* pre-made file handle to fill in */
uint32_t *cr_act_p, /* optional returned create action */
struct smbfattr *fap) /* optional returned attributes */
{
@@ -1153,7 +326,7 @@ smbfs_smb_ntcreatex(
0, /* NTCREATEX_FLAGS... */
req_acc, efa, share_acc, disp, createopt,
NTCREATEX_IMPERSONATION_IMPERSONATION,
- scrp, fidp, cr_act_p, fap);
+ scrp, fhp, cr_act_p, fap);
out:
mb_done(&name_mb);
@@ -1161,233 +334,68 @@ out:
return (err);
}
-static uint32_t
-smb_mode2rights(int mode)
-{
- mode = mode & SMB_AM_OPENMODE;
- uint32_t rights =
- STD_RIGHT_SYNCHRONIZE_ACCESS |
- STD_RIGHT_READ_CONTROL_ACCESS;
-
- if ((mode == SMB_AM_OPENREAD) ||
- (mode == SMB_AM_OPENRW)) {
- rights |=
- SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_READ_DATA;
- }
-
- if ((mode == SMB_AM_OPENWRITE) ||
- (mode == SMB_AM_OPENRW)) {
- rights |=
- SA_RIGHT_FILE_WRITE_ATTRIBUTES |
- SA_RIGHT_FILE_APPEND_DATA |
- SA_RIGHT_FILE_WRITE_DATA;
- }
-
- if (mode == SMB_AM_OPENEXEC) {
- rights |=
- SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_EXECUTE;
- }
-
- return (rights);
-}
-
-static int
-smb_rights2mode(uint32_t rights)
-{
- int accmode = SMB_AM_OPENEXEC; /* our fallback */
-
- if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
- SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
- SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
- STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
- accmode = SMB_AM_OPENWRITE;
- if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
- accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
- : SMB_AM_OPENRW;
- return (accmode);
-}
-
-static int
-smbfs_smb_oldopen(
- struct smbnode *np,
- const char *name,
- int nmlen,
- int xattr,
- int accmode,
- struct smb_cred *scrp,
- uint16_t *fidp,
- uint16_t *granted_mode_p,
- smbfattr_t *fap)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct smbfattr fa;
- uint8_t wc;
- uint16_t wattr;
- uint32_t longint;
- int error;
-
- bzero(&fa, sizeof (fa));
-
- /*
- * XXX: move to callers...
- *
- * Use DENYNONE to give unixy semantics of permitting
- * everything not forbidden by permissions. Ie denial
- * is up to server with clients/openers needing to use
- * advisory locks for further control.
- */
- accmode |= SMB_SM_DENYNONE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, accmode);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
- SMB_FA_DIR);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto done;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto done;
- smb_rq_getreply(rqp, &mdp);
- /*
- * 8/2002 a DAVE server returned wc of 15 so we ignore that.
- * (the actual packet length and data was correct)
- */
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto done;
- if (wc != 7 && wc != 15) {
- error = EBADRPC;
- goto done;
- }
- md_get_uint16le(mdp, fidp);
- md_get_uint16le(mdp, &wattr);
- fa.fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
- md_get_uint32le(mdp, &longint);
- fa.fa_size = longint;
- error = md_get_uint16le(mdp, granted_mode_p);
-
-done:
- smb_rq_done(rqp);
- if (error)
- return (error);
-
- if (fap)
- *fap = fa; /* struct copy */
-
- return (0);
-}
-
+/*
+ * Get a file handle with (at least) the specified rights.
+ *
+ * We'll try to borrow the node ->n_fid if we can. When we
+ * borrow n_fid, just take a hold on the smb_fh_t, and don't
+ * bump n_fidrefs as that tracks VFS-level opens. Similarly
+ * in _tmpclose we just release the smb_fh_t, not n_fidrefs.
+ */
int
smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
- uint16_t *fidp)
+ smb_fh_t **fhpp)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- int accmode, error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ smb_fh_t *fhp = NULL;
+ int error;
/* Can we re-use n_fid? or must we open anew? */
mutex_enter(&np->r_statelock);
if (np->n_fidrefs > 0 &&
- np->n_vcgenid == ssp->ss_vcgenid &&
- (rights & np->n_rights) == rights) {
- np->n_fidrefs++;
- *fidp = np->n_fid;
+ (fhp = np->n_fid) != NULL &&
+ fhp->fh_vcgenid == ssp->ss_vcgenid &&
+ (fhp->fh_rights & rights) == rights) {
+ smb_fh_hold(fhp);
+ *fhpp = fhp;
mutex_exit(&np->r_statelock);
return (0);
}
mutex_exit(&np->r_statelock);
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/* re-open an existing file. */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_ntcreatex(np,
- NULL, 0, 0, /* name nmlen xattr */
- rights, SMB_EFA_NORMAL,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_OPEN,
- 0, /* create options */
- scrp, fidp,
- NULL, NULL); /* cr_act_p fa_p */
- return (error);
- }
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp,
+ NULL, NULL); /* cr_act_p fa_p */
+ if (error != 0)
+ goto out;
+
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
- accmode = smb_rights2mode(rights);
- error = smbfs_smb_oldopen(np,
- NULL, 0, 0, /* name nmlen xattr */
- accmode, scrp,
- fidp,
- NULL, /* granted mode p */
- NULL); /* fa p */
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
return (error);
}
-int
-smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
+/* ARGSUSED */
+void
+smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- int error = 0;
- uint16_t oldfid = SMB_FID_UNUSED;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- mutex_enter(&np->r_statelock);
- if (fid == np->n_fid) {
- ASSERT(np->n_fidrefs > 0);
- if (--np->n_fidrefs == 0) {
- /*
- * Don't expect to find the last reference
- * here in tmpclose. Hard to deal with as
- * we don't have r_lkserlock exclusive.
- * Will close oldfid below.
- */
- oldfid = np->n_fid;
- np->n_fid = SMB_FID_UNUSED;
- }
- } else {
- /* Will close the passed fid. */
- oldfid = fid;
- }
- mutex_exit(&np->r_statelock);
-
- if (oldfid != SMB_FID_UNUSED)
- error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
-
- return (error);
+ smb_fh_rele(fhp);
}
int
@@ -1398,124 +406,47 @@ smbfs_smb_open(
int xattr,
uint32_t rights,
struct smb_cred *scrp,
- uint16_t *fidp,
- uint32_t *rightsp,
+ smb_fh_t **fhpp,
smbfattr_t *fap)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- int accmode, error;
- uint16_t grantedmode;
-
- /* open an existing file */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_ntcreatex(np,
- name, nmlen, xattr,
- rights, SMB_EFA_NORMAL,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_OPEN,
- 0, /* create options */
- scrp, fidp,
- NULL, fap); /* cr_act_p fa_p */
- if (error != 0)
- return (error);
- *rightsp = rights;
- return (0);
- }
+ // struct smb_vc *vcp = SSTOVC(ssp);
+ smb_fh_t *fhp = NULL;
+ int error;
- accmode = smb_rights2mode(rights);
- error = smbfs_smb_oldopen(np,
- name, nmlen, xattr, accmode, scrp,
- fidp, &grantedmode, fap);
+ error = smb_fh_create(ssp, &fhp);
if (error != 0)
- return (error);
- *rightsp = smb_mode2rights(grantedmode);
- (void) smbfs_smb_getfattr(np, fap, scrp);
+ goto out;
- return (0);
-}
+ /* open an existing file */
+ error = smbfs_smb_ntcreatex(np,
+ name, nmlen, xattr,
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp, NULL, fap);
+ if (error != 0)
+ goto out;
-int
-smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
- struct timespec *mtime, struct smb_cred *scrp)
-{
- int error;
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
- error = smb_smb_close(ssp, fid, mtime, scrp);
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
- /*
- * ENOTCONN isn't interesting - if the connection is closed,
- * so are all our FIDs - and EIO is also not interesting,
- * as it means a forced unmount was done. (was ENXIO)
- * Also ETIME, which means we sent the request but gave up
- * waiting before the response came back.
- *
- * Don't clog up the system log with warnings about these
- * uninteresting failures on closes.
- */
- switch (error) {
- case ENOTCONN:
- case ENXIO:
- case EIO:
- case ETIME:
- error = 0;
- }
- return (error);
+ return (0);
}
-static int
-smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, struct smb_cred *scrp, uint16_t *fidp)
+void
+smbfs_smb_close(smb_fh_t *fhp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct timespec ctime;
- uint8_t wc;
- long tm;
- int error;
- uint16_t attr = SMB_FA_ARCHIVE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- if (name && *name == '.')
- attr |= SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, attr); /* attributes */
- gethrestime(&ctime);
- smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
- mb_put_uint32le(mbp, tm);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto out;
-
- smb_rq_getreply(rqp, &mdp);
- md_get_uint8(mdp, &wc);
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, fidp);
-out:
- smb_rq_done(rqp);
- return (error);
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
}
int
@@ -1526,759 +457,127 @@ smbfs_smb_create(
int xattr,
uint32_t disp,
struct smb_cred *scrp,
- uint16_t *fidp)
+ smb_fh_t **fhpp)
{
struct smb_share *ssp = dnp->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
+ // struct smb_vc *vcp = SSTOVC(ssp);
+ smb_fh_t *fhp = NULL;
uint32_t efa, rights;
int error;
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/*
* At present the only access we might need is to WRITE data,
* and that only if we are creating a "symlink". When/if the
* access needed gets more complex it should made a parameter
* and be set upstream.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- rights = SA_RIGHT_FILE_WRITE_DATA;
- efa = SMB_EFA_NORMAL;
- if (!xattr && name && *name == '.')
- efa = SMB_EFA_HIDDEN;
- error = smbfs_smb_ntcreatex(dnp,
- name, nmlen, xattr, rights, efa,
- NTCREATEX_SHARE_ACCESS_ALL,
- disp, /* != NTCREATEX_DISP_OPEN */
- NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
- scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
- return (error);
- }
+ rights = SA_RIGHT_FILE_WRITE_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (!xattr && name && *name == '.')
+ efa = SMB_EFA_HIDDEN;
+ error = smbfs_smb_ntcreatex(dnp,
+ name, nmlen, xattr, rights, efa,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ disp, /* != NTCREATEX_DISP_OPEN */
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ scrp, fhp, NULL, NULL);
+ if (error != 0)
+ goto out;
- error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
- return (error);
-}
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
-int
-smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
- int nmlen, int xattr)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
- xattr ? ':' : '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
return (error);
}
int
-smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp)
+smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np,
+ struct smbnode *tdnp, const char *tname, int tnlen,
+ smb_fh_t *fhp, struct smb_cred *scrp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
- uint16_t fa;
- char sep;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
- fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
- fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, fa);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ int err;
- /*
- * When we're not adding any component name, the
- * passed sep is ignored, so just pass sep=0.
- */
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
- if (error)
- goto out;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0,
+ &fhp->fh_fid2, scrp);
+ return (err);
+ }
/*
- * After XATTR directories, separator is ":"
+ * SMB1 -- Want to use _t2rename if we can
+ * (rename in same dir and cap pass-through)
+ * Most SMB1 servers have cap pass-through.
*/
- sep = (src->n_flag & N_XATTR) ? ':' : '\\';
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
- if (error)
- goto out;
-
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
- mb_put_uint16le(mbp, 0x20); /* delete target file */
- mb_put_uint16le(mbp, flags);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-static int
-smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
+ if (sdnp == tdnp &&
+ (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) {
+ err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp);
+ } else {
+ err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp);
}
- smb_rq_done(rqp);
- return (error);
+
+ return (err);
}
int
smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
struct smb_cred *scrp)
{
+ smb_fh_t tmp_fh;
struct smb_share *ssp = dnp->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- uint32_t rights;
- uint16_t fid;
+ uint32_t efa, rights;
int error;
/*
+ * Using a faked-up handle here to avoid the work of
+ * creating and destroying a real "conn obj".
+ */
+ bzero(&tmp_fh, sizeof (tmp_fh));
+
+ /*
* We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
* just to be asking for something. The rights==0 case could
* easily be broken on some old or unusual servers.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- rights = SA_RIGHT_FILE_READ_DATA;
- error = smbfs_smb_ntcreatex(dnp,
- name, nmlen, 0, /* xattr */
- rights, SMB_EFA_DIRECTORY,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_CREATE,
- NTCREATEX_OPTIONS_DIRECTORY,
- scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
- if (error)
- return (error);
- (void) smbfs_smb_close(ssp, fid, NULL, scrp);
- return (0);
+ rights = SA_RIGHT_FILE_READ_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (name && *name == '.')
+ efa |= SMB_EFA_HIDDEN;
+ error = smbfs_smb_ntcreatex(dnp,
+ name, nmlen, 0, /* xattr */
+ rights, SMB_EFA_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY,
+ scrp, &tmp_fh, NULL, NULL);
+ if (error == 0) {
+ (void) smb_smb_close(ssp, &tmp_fh, scrp);
}
- error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
- return (error);
-}
-
-int
-smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
return (error);
}
-static int
-smbfs_smb_search(struct smbfs_fctx *ctx)
-{
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc, bt;
- uint16_t ec, dlen, bc;
- int maxent, error, iseof = 0;
-
- maxent = min(ctx->f_left,
- (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
- if (ctx->f_rq) {
- smb_rq_done(ctx->f_rq);
- ctx->f_rq = NULL;
- }
- error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
- ctx->f_scred, &rqp);
- if (error)
- return (error);
- ctx->f_rq = rqp;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, maxent); /* max entries to return */
- mb_put_uint16le(mbp, ctx->f_attrmask);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, 0); /* context length */
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- } else {
- if (SMB_UNICODE_STRINGS(vcp)) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0);
- }
- mb_put_uint8(mbp, 0);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, SMB_SKEYLEN);
- mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- }
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
- error = 0;
- iseof = 1;
- ctx->f_flags |= SMBFS_RDD_EOF;
- } else if (error)
- return (error);
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- return (error);
- if (wc != 1)
- return (iseof ? ENOENT : EBADRPC);
- md_get_uint16le(mdp, &ec);
- md_get_uint16le(mdp, &bc);
- md_get_uint8(mdp, &bt);
- error = md_get_uint16le(mdp, &dlen);
- if (error)
- return (error);
- if (ec == 0)
- return (ENOENT);
- ctx->f_ecnt = ec;
- if (bc < 3)
- return (EBADRPC);
- bc -= 3;
- if (bt != SMB_DT_VARIABLE)
- return (EBADRPC);
- if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
- return (EBADRPC);
- return (0);
-}
-
-
-/*ARGSUSED*/
-static int
-smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
-{
-
- ctx->f_type = ft_LM1;
- ctx->f_attrmask = attr;
- if (wildcard) {
- if (wclen == 1 && wildcard[0] == '*') {
- ctx->f_wildcard = "*.*";
- ctx->f_wclen = 3;
- } else {
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- }
- } else {
- ctx->f_wildcard = NULL;
- ctx->f_wclen = 0;
- }
- ctx->f_name = (char *)ctx->f_fname;
- ctx->f_namesz = 0;
- return (0);
-}
-
-static int
-smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
-{
- struct mdchain *mdp;
- struct smb_rq *rqp;
- char *cp;
- uint8_t battr;
- uint16_t date, time;
- uint32_t size;
- int error;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_search(ctx);
- if (error)
- return (error);
- }
- rqp = ctx->f_rq;
- smb_rq_getreply(rqp, &mdp);
- md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- md_get_uint8(mdp, &battr);
- md_get_uint16le(mdp, &time);
- md_get_uint16le(mdp, &date);
- md_get_uint32le(mdp, &size);
- cp = ctx->f_name;
- error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
- cp[sizeof (ctx->f_fname) - 1] = 0;
- cp += strlen(cp) - 1;
- while (*cp == ' ' && cp >= ctx->f_name)
- *cp-- = 0;
- ctx->f_attr.fa_attr = battr;
- smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
- &ctx->f_attr.fa_mtime);
- ctx->f_attr.fa_size = size;
- ctx->f_nmlen = strlen(ctx->f_name);
- ctx->f_ecnt--;
- ctx->f_left--;
- return (0);
-}
-
-static int
-smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
-{
- if (ctx->f_rq)
- smb_rq_done(ctx->f_rq);
- return (0);
-}
-
/*
- * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ * Protocol-level directory open
*/
-static int
-smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
-{
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t ecnt, eos, lno, flags;
- int error;
-
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
- flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- flags |= FIND2_CLOSE_AFTER_REQUEST;
- ctx->f_flags |= SMBFS_RDD_NOCLOSE;
- }
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_attrmask);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, flags);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- } else {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- /* Send whatever resume key we received... */
- mb_put_uint32le(mbp, ctx->f_rkey);
- mb_put_uint16le(mbp, flags);
- /* ... and the resume name if we have one. */
- if (ctx->f_rname) {
- /* resume file name */
- mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
- MB_MSYSTEM);
- }
- /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
- mb_put_uint8(mbp, 0);
- }
- t2p->t2_maxpcount = 5 * 2;
- t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
- error = smb_t2_request(t2p);
- if (error)
- return (error);
-
- /*
- * This is the "resume name" we just sent.
- * We want the new one (if any) that may be
- * found in the response we just received and
- * will now begin parsing. Free the old one
- * now so we'll know if we found a new one.
- */
- if (ctx->f_rname) {
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = NULL;
- ctx->f_rnamelen = 0;
- }
-
- mdp = &t2p->t2_rparam;
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
- goto nodata;
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- }
- md_get_uint16le(mdp, &ecnt); /* entry count */
- md_get_uint16le(mdp, &eos); /* end of search */
- md_get_uint16le(mdp, NULL); /* EA err. off. */
- error = md_get_uint16le(mdp, &lno); /* last name off. */
- if (error != 0)
- goto nodata;
-
- /*
- * The "end of search" flag from an XP server sometimes
- * comes back zero when the prior find_next returned exactly
- * the number of entries requested. in which case we'd try again
- * but the search has in fact been closed so an EBADF results.
- * our circumvention is to check here for a zero entry count.
- */
- ctx->f_ecnt = ecnt;
- if (eos || ctx->f_ecnt == 0)
- ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
- if (ctx->f_ecnt == 0)
- return (ENOENT);
-
- /* Last Name Off (LNO) is the entry with the resume name. */
- ctx->f_rnameofs = lno;
- ctx->f_eofs = 0;
- return (0);
-
-nodata:
- /*
- * Failed parsing the FindFirst or FindNext response.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
-}
-
-static int
-smbfs_smb_findclose2(struct smbfs_fctx *ctx)
-{
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
- ctx->f_scred);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- /* Ditto comments at _smb_close */
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
-}
-
-/*ARGSUSED*/
-static int
-smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
-{
-
- ctx->f_type = ft_LM2;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
- ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
- < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
- SMB_FIND_BOTH_DIRECTORY_INFO;
- ctx->f_attrmask = attr;
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- return (0);
-}
-
-static int
-smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
-{
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- char *cp;
- uint8_t tb;
- uint16_t date, time, wattr;
- uint32_t size, next, dattr, resumekey = 0;
- uint64_t llongint;
- int error, svtz, cnt, fxsz, nmlen, recsz;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_trans2find2(ctx);
- if (error)
- return (error);
- ctx->f_otws++;
- }
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
- svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
- switch (ctx->f_infolevel) {
- case SMB_FIND_STANDARD:
- next = 0;
- fxsz = 0;
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz,
- &ctx->f_attr.fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
- md_get_uint32le(mdp, &size);
- ctx->f_attr.fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- ctx->f_attr.fa_allocsz = size;
- md_get_uint16le(mdp, &wattr);
- ctx->f_attr.fa_attr = wattr;
- error = md_get_uint8(mdp, &tb);
- if (error)
- goto nodata;
- size = nmlen = tb;
- fxsz = 23;
- recsz = next = 24 + nmlen; /* docs misses zero byte @end */
- break;
- case SMB_FIND_DIRECTORY_INFO:
- case SMB_FIND_BOTH_DIRECTORY_INFO:
- md_get_uint32le(mdp, &next);
- md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
- md_get_uint64le(mdp, &llongint); /* creation time */
- smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
- md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- md_get_uint64le(mdp, &llongint); /* alloc. size */
- ctx->f_attr.fa_allocsz = llongint;
- md_get_uint32le(mdp, &dattr); /* ext. file attributes */
- ctx->f_attr.fa_attr = dattr;
- error = md_get_uint32le(mdp, &size); /* name len */
- if (error)
- goto nodata;
- fxsz = 64; /* size ofinfo up to filename */
- if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
- /*
- * Skip EaSize(4 bytes), a byte of ShortNameLength,
- * a reserved byte, and ShortName(8.3 means 24 bytes,
- * as Leach defined it to always be Unicode)
- */
- error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
- if (error)
- goto nodata;
- fxsz += 30;
- }
- recsz = next ? next : fxsz + size;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
- return (EINVAL);
- }
-
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- else
- nmlen = min(size, SMB_MAXFNAMELEN);
-
- /* Allocated f_name in findopen */
- ASSERT(nmlen < ctx->f_namesz);
- cp = ctx->f_name;
-
- error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
- if (error)
- goto nodata;
- if (next) {
- /* How much data to skip? */
- cnt = next - nmlen - fxsz;
- if (cnt < 0) {
- SMBVDEBUG("out of sync\n");
- goto nodata;
- }
- if (cnt > 0)
- md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
- }
- /* Don't count any trailing null in the name. */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
- nmlen -= 2;
- } else {
- if (nmlen && cp[nmlen - 1] == 0)
- nmlen--;
- }
- if (nmlen == 0)
- goto nodata;
-
- /*
- * On a find-next we expect that the server will:
- * 1) if the continue bit is set, use the server's offset,
- * 2) else if the resume key is non-zero, use that offset,
- * 3) else if the resume name is set, use that offset,
- * 4) else use the server's idea of current offset.
- *
- * We always set the resume key flag. If the server returns
- * a resume key then we should always send it back to them.
- */
- ctx->f_rkey = resumekey;
-
- next = ctx->f_eofs + recsz;
- if (ctx->f_rnameofs &&
- ctx->f_rnameofs >= ctx->f_eofs &&
- ctx->f_rnameofs < (int)next) {
- /*
- * This entry is the "resume name".
- * Save it for the next request.
- */
- if (ctx->f_rnamelen != nmlen) {
- if (ctx->f_rname)
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
- ctx->f_rnamelen = nmlen;
- }
- bcopy(ctx->f_name, ctx->f_rname, nmlen);
- }
- ctx->f_nmlen = nmlen;
- ctx->f_eofs = next;
- ctx->f_ecnt--;
- ctx->f_left--;
-
- smbfs_fname_tolocal(ctx);
- return (0);
-
-nodata:
- /*
- * Something bad has happened and we ran out of data
- * before we could parse all f_ecnt entries expected.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- SMBVDEBUG("ran out of data\n");
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
-}
-
-static int
-smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
-{
- int error = 0;
- if (ctx->f_name)
- kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
- /*
- * If SMBFS_RDD_FINDFIRST is still set, we were opened
- * but never saw a findfirst, so we don't have any
- * search handle to close.
- */
- if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
- error = smbfs_smb_findclose2(ctx);
- return (error);
-}
-
int
smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
int attr, struct smb_cred *scrp,
struct smbfs_fctx **ctxpp)
{
+ struct smb_share *ssp = dnp->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
struct smbfs_fctx *ctx;
int error;
@@ -2287,50 +586,56 @@ smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
ctx->f_flags = SMBFS_RDD_FINDFIRST;
ctx->f_dnp = dnp;
ctx->f_scred = scrp;
- ctx->f_ssp = dnp->n_mount->smi_share;
+ ctx->f_ssp = ssp;
if (dnp->n_flag & N_XATTR) {
error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
goto out;
}
- if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
- error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr);
} else {
error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
}
out:
- if (error)
- (void) smbfs_smb_findclose(ctx, scrp);
- else
+ ctx->f_scred = NULL;
+ if (error) {
+ kmem_free(ctx, sizeof (*ctx));
+ } else {
*ctxpp = ctx;
+ }
+
return (error);
}
int
smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
{
- int error;
+ int error = 0;
+ uint16_t lim;
/*
* Note: "limit" (maxcount) needs to fit in a short!
*/
if (limit > 0xffff)
limit = 0xffff;
+ lim = (uint16_t)limit;
ctx->f_scred = scrp;
for (;;) {
bzero(&ctx->f_attr, sizeof (ctx->f_attr));
switch (ctx->f_type) {
- case ft_LM1:
- error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
+
+ case ft_SMB2:
+ error = smbfs_smb2_findnext(ctx, lim);
break;
case ft_LM2:
- error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
+ error = smbfs_smb_findnextLM2(ctx, lim);
break;
case ft_XA:
- error = smbfs_xa_findnext(ctx, (uint16_t)limit);
+ error = smbfs_xa_findnext(ctx, lim);
break;
default:
ASSERT(0);
@@ -2338,7 +643,7 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
break;
}
if (error)
- return (error);
+ break;
/*
* Skip "." or ".." - easy now that ctx->f_name
* has already been converted to utf-8 format.
@@ -2349,14 +654,18 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
continue;
break;
}
+ ctx->f_scred = NULL;
+ if (error != 0)
+ return (error);
- /*
- * Moved the smbfs_fname_tolocal(ctx) call into
- * the ..._findnext functions above.
- */
+ ctx->f_inum = smbfs_getino(ctx->f_dnp,
+ ctx->f_name, ctx->f_nmlen);
- ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
- return (0);
+#ifdef DEBUG
+ SMBVDEBUG("findnext: (%s)\n", ctx->f_name);
+#endif
+
+ return (error);
}
@@ -2367,8 +676,8 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
ctx->f_scred = scrp;
switch (ctx->f_type) {
- case ft_LM1:
- error = smbfs_smb_findcloseLM1(ctx);
+ case ft_SMB2:
+ error = smbfs_smb2_findclose(ctx);
break;
case ft_LM2:
error = smbfs_smb_findcloseLM2(ctx);
@@ -2376,7 +685,11 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
case ft_XA:
error = smbfs_xa_findclose(ctx);
break;
+ default:
+ error = ENOSYS;
+ break;
}
+ ctx->f_scred = NULL;
if (ctx->f_rname)
kmem_free(ctx->f_rname, ctx->f_rnamelen);
if (ctx->f_firstnm)
@@ -2416,25 +729,12 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
}
/*
- * XXX: Should use _qpathinfo here instead.
- * (if SMB_CAP_NT_SMBS)
- */
-
- /*
* Shared lock for n_fid use (smb_flush).
*/
intr = dnp->n_mount->smi_flags & SMI_INT;
if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
return (EINTR);
- /*
- * This hides a server bug observable in Win98:
- * size changes may not show until a CLOSE or a FLUSH op
- * XXX: Make this conditional on !NTSMBs
- */
- error = smbfs_smb_flush(dnp, scrp);
- if (error)
- goto out;
error = smbfs_smb_findopen(dnp, name, nmlen,
SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
if (error)
@@ -2468,148 +768,49 @@ out:
* which the caller should free.
*/
int
-smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector,
- mblk_t **res, uint32_t *reslen)
+smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
{
- struct smb_ntrq *ntp;
- struct mbchain *mbp;
- struct mdchain *mdp;
+ struct smb_vc *vcp = SSTOVC(ssp);
int error, len;
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
- /* Data part (none) */
-
- /* Max. returned parameters and data. */
- ntp->nt_maxpcount = 4;
- ntp->nt_maxdcount = *reslen;
-
- error = smb_nt_request(ntp);
- if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
- goto done;
*res = NULL;
- /*
- * if there's more data than we said we could receive, here
- * is where we pick up the length of it
- */
- mdp = &ntp->nt_rparam;
- md_get_uint32le(mdp, reslen);
- if (error)
- goto done;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2,
+ selector, res, reslen, scrp);
+ } else {
+ error = smbfs_smb1_getsec(ssp, fhp->fh_fid1,
+ selector, res, reslen, scrp);
+ }
/*
* get the data part.
*/
- mdp = &ntp->nt_rdata;
- if (mdp->md_top == NULL) {
- SMBVDEBUG("null md_top? fid 0x%x\n", fid);
+ if (*res == NULL) {
error = EBADRPC;
goto done;
}
/*
- * The returned parameter SD_length should match
- * the length of the returned data. Unfortunately,
- * we have to work around server bugs here.
- */
- len = m_fixhdr(mdp->md_top);
- if (len != *reslen) {
- SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
- len, *reslen, fid);
- }
-
- /*
- * Actual data provided is < returned SD_length.
- *
- * The following "if (len < *reslen)" handles a Windows bug
- * observed when the underlying filesystem is FAT32. In that
- * case a 32 byte security descriptor comes back (S-1-1-0, ie
- * "Everyone") but the Parameter Block claims 44 is the length
- * of the security descriptor. (The Data Block length
- * claimed is 32. This server bug was reported against NT
- * first and I've personally observed it with W2K.
+ * If message length is < returned SD_length,
+ * correct *reslen (reduce it). It greater,
+ * just ignore the extra data.
*/
+ len = m_fixhdr(*res);
if (len < *reslen)
*reslen = len;
- /*
- * Actual data provided is > returned SD_length.
- * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
- * Narrow work-around for returned SD_length==0.
- */
- if (len > *reslen) {
- /*
- * Increase *reslen, but carefully.
- */
- if (*reslen == 0 && len <= ntp->nt_maxdcount)
- *reslen = len;
- }
- error = md_get_mbuf(mdp, len, res);
-
done:
if (error == 0 && *res == NULL) {
ASSERT(*res);
error = EBADRPC;
}
- smb_nt_done(ntp);
return (error);
}
-#ifdef APPLE
-/*
- * Wrapper for _getsd() compatible with darwin code.
- */
-int
-smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, struct ntsecdesc **res)
-{
- int error;
- uint32_t len, olen;
- struct mdchain *mdp, md_store;
- struct mbuf *m;
-
- bzero(mdp, sizeof (*mdp));
- len = 500; /* "overlarge" values => server errors */
-again:
- olen = len;
- error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
- /*
- * Server may give us an error indicating that we
- * need a larger data buffer to receive the SD,
- * and the size we'll need. Use the given size,
- * but only after a sanity check.
- *
- * XXX: Check for specific error values here?
- * XXX: also ... && len <= MAX_RAW_SD_SIZE
- */
- if (error && len > olen)
- goto again;
-
- if (error)
- return (error);
-
- mdp = &md_store;
- md_initm(mdp, m);
- MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
- error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
- md_done(mdp);
-
- return (error);
-}
-#endif /* APPLE */
-
/*
* OTW function to Set a security descriptor (SD).
* Caller data are carried in an mbchain_t.
@@ -2617,108 +818,21 @@ again:
* Note: This normally consumes mbp->mb_top, and clears
* that pointer when it does.
*/
-int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
-{
- struct smb_ntrq *ntp;
- struct mbchain *mbp;
- int error;
-
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
-
- /* Data part */
- mbp = &ntp->nt_tdata;
- mb_initm(mbp, *mp);
- *mp = NULL; /* consumed */
-
- /* No returned parameters or data. */
- ntp->nt_maxpcount = 0;
- ntp->nt_maxdcount = 0;
-
- error = smb_nt_request(ntp);
- smb_nt_done(ntp);
-
- return (error);
-}
-
-#ifdef APPLE
-/*
- * This function builds the SD given the various parts.
- */
int
-smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, uint16_t flags, struct ntsid *owner,
- struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
+smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp)
{
- struct mbchain *mbp, mb_store;
- struct ntsecdesc ntsd;
- int error, off;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ int error;
- /*
- * Build the SD as its own mbuf chain and pass it to
- * smbfs_smb_setsec_m()
- */
- mbp = &mb_store;
- mb_init(mbp);
- bzero(&ntsd, sizeof (ntsd));
- wset_sdrevision(&ntsd);
- /*
- * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
- * We set here only those bits we can be sure must be set. The rest
- * are up to the caller. In particular, the caller may intentionally
- * set an acl PRESENT bit while giving us a null pointer for the
- * acl - that sets a null acl, giving access to everyone. Note also
- * that the AUTO_INHERITED bits should probably always be set unless
- * the server is NT.
- */
- flags |= SD_SELF_RELATIVE;
- off = sizeof (ntsd);
- if (owner) {
- wset_sdowneroff(&ntsd, off);
- off += sidlen(owner);
- }
- if (group) {
- wset_sdgroupoff(&ntsd, off);
- off += sidlen(group);
- }
- if (sacl) {
- flags |= SD_SACL_PRESENT;
- wset_sdsacloff(&ntsd, off);
- off += acllen(sacl);
- }
- if (dacl) {
- flags |= SD_DACL_PRESENT;
- wset_sddacloff(&ntsd, off);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2,
+ selector, mp, scrp);
+ } else {
+ error = smbfs_smb1_setsec(ssp, fhp->fh_fid1,
+ selector, mp, scrp);
}
- wset_sdflags(&ntsd, flags);
- mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
- if (owner)
- mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
- if (group)
- mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
- if (sacl)
- mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
- if (dacl)
- mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
-
- /*
- * Just pass the mbuf to _setsec_m
- * It will clear mb_top if consumed.
- */
- error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
- mb_done(mbp);
return (error);
}
-
-#endif /* APPLE */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c
new file mode 100644
index 0000000000..6c00816133
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c
@@ -0,0 +1,926 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/inttypes.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#if 0 // todo
+
+int
+smbfs_smb1_lockandx(struct smbnode *np, int op, uint32_t pid,
+ offset_t start, uint64_t len, int largelock,
+ struct smb_cred *scrp, uint32_t timeout)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ uint8_t ltype = 0;
+ int error;
+
+ /* Shared lock for n_fid use below. */
+ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ if (op == SMB_LOCK_SHARED)
+ ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
+ /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
+ if (largelock)
+ ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff); /* secondary command */
+ mb_put_uint8(mbp, 0); /* MBZ */
+ mb_put_uint16le(mbp, 0);
+ mb_put_uint16le(mbp, np->n_fid);
+ mb_put_uint8(mbp, ltype); /* locktype */
+ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
+ mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
+ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
+ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ mb_put_uint16le(mbp, pid);
+ if (!largelock) {
+ mb_put_uint32le(mbp, start);
+ mb_put_uint32le(mbp, len);
+ } else {
+ mb_put_uint16le(mbp, 0); /* pad */
+ mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
+ mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
+ mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
+ mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
+ }
+ smb_rq_bend(rqp);
+ /*
+ * Don't want to risk missing a successful
+ * unlock send or lock response, or we could
+ * lose track of an outstanding lock.
+ */
+ if (op == SMB_LOCK_RELEASE)
+ rqp->sr_flags |= SMBR_NOINTR_SEND;
+ else
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+#endif // todo
+
+/*
+ * Common function for QueryFileInfo, QueryPathInfo.
+ */
+int
+smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
+ struct smbfattr *fap, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t cmd;
+ uint16_t infolevel = SMB_QFILEINFO_ALL_INFO;
+ int error;
+
+ /*
+ * If we have a valid open FID, use it.
+ */
+ if (fid != SMB_FID_UNUSED)
+ cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
+ else
+ cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+
+ if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
+ mb_put_uint16le(mbp, fid);
+
+ mb_put_uint16le(mbp, infolevel);
+
+ if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
+ mb_put_uint32le(mbp, 0);
+ /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
+ error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
+ if (error)
+ goto out;
+ }
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = vcp->vc_txmax;
+ error = smb_t2_request(t2p);
+ if (error)
+ goto out;
+
+ /*
+ * Parse the SMB_QFILEINFO_ALL_INFO
+ */
+ mdp = &t2p->t2_rdata;
+ error = smbfs_decode_file_all_info(ssp, mdp, fap);
+
+out:
+ smb_t2_done(t2p);
+
+ return (error);
+}
+
+/*
+ * Get some FS information
+ */
+static int
+smbfs_smb1_query_fs_info(struct smb_share *ssp, struct mdchain *info_mdp,
+ uint16_t level, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
+ scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, level);
+ t2p->t2_maxpcount = 4;
+ t2p->t2_maxdcount = 1024;
+ error = smb_t2_request(t2p);
+ if (error)
+ goto out;
+
+ mdp = &t2p->t2_rdata;
+ *info_mdp = *mdp;
+ bzero(mdp, sizeof (*mdp));
+
+out:
+ smb_t2_done(t2p);
+ return (error);
+}
+
+/*
+ * Get FILE_FS_ATTRIBUTE_INFORMATION
+ */
+int
+smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb1_query_fs_info(ssp, mdp,
+ SMB_QFS_ATTRIBUTE_INFO, scrp);
+ if (error)
+ goto out;
+ error = smbfs_decode_fs_attr_info(ssp, mdp, fsa);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsFullSizeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb1_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint16_t level;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_QFS_FULL_SIZE_INFORMATION;
+ else
+ level = SMB_QFS_SIZE_INFO;
+ error = smbfs_smb1_query_fs_info(ssp, mdp, level, scrp);
+ if (error)
+ goto out;
+
+ md_get_uint64le(mdp, &info->total_units);
+ md_get_uint64le(mdp, &info->caller_avail);
+ if (level == SMB_QFS_FULL_SIZE_INFORMATION)
+ md_get_uint64le(mdp, &info->actual_avail);
+ else
+ info->actual_avail = info->caller_avail;
+
+ md_get_uint32le(mdp, &info->sect_per_unit);
+ error = md_get_uint32le(mdp, &info->bytes_per_sect);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+int
+smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, fid);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*
+ * Set file info via an open handle.
+ * Caller provides payload, info level.
+ */
+static int
+smbfs_smb1_setinfo_file(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *info_mbp, uint16_t level, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p = NULL;
+ struct mbchain *mbp;
+ uint16_t cmd = SMB_TRANS2_SET_FILE_INFORMATION;
+ int error;
+
+ ASSERT(fid != SMB_FID_UNUSED);
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, level);
+ mb_put_uint16le(mbp, 0); /* pad */
+
+ /* put the payload */
+ mbp = &t2p->t2_tdata;
+ mb_init(mbp);
+ error = mb_put_mbchain(mbp, info_mbp);
+ if (error)
+ goto out;
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = 0;
+ error = smb_t2_request(t2p);
+
+out:
+ smb_t2_done(t2p);
+
+ return (error);
+}
+
+int
+smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid,
+ uint64_t newsize, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
+ else
+ level = SMB_SFILEINFO_END_OF_FILE_INFO;
+
+ mb_init(mbp);
+ error = mb_put_uint64le(mbp, newsize);
+ if (error)
+ goto out;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+ return (error);
+}
+
+int
+smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid,
+ uint8_t newdisp, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
+ else
+ level = SMB_SFILEINFO_DISPOSITION_INFO;
+
+ mb_init(mbp);
+ error = mb_put_uint8(mbp, newdisp);
+ if (error)
+ goto out;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Set FileBasicInformation on an open handle
+ * Caller builds the mbchain.
+ * Always have a FID here.
+ */
+int
+smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *mbp, struct smb_cred *scrp)
+{
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_BASIC_INFORMATION;
+ else
+ level = SMB_SFILEINFO_BASIC_INFO;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+ return (error);
+}
+
+/*
+ * On SMB1, the trans2 rename only allows a rename where the
+ * source and target are in the same directory. If you give
+ * the server any separators, you get "status not supported".
+ *
+ * Why bother using this instead of smbfs_smb1_oldrename?
+ * Because it works with an open file, and some servers don't
+ * allow oldrename of a file that's currently open. We call
+ * this when deleting an open file in smbfsremove(), where
+ * the rename is always in the same directory.
+ */
+/*ARGSUSED*/
+int
+smbfs_smb1_t2rename(struct smbnode *np,
+ const char *tname, int tnlen,
+ uint16_t fid, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct mbchain data_mb, *mbp = &data_mb;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t *name_lenp;
+ uint16_t level = SMB_SFILEINFO_RENAME_INFORMATION;
+ int base, len;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint32le(mbp, 0); /* don't overwrite */
+ mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ name_lenp = mb_reserve(mbp, 4); /* name len */
+
+ /* New name */
+ base = mbp->mb_count;
+ error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
+ if (error)
+ goto out;
+ len = mbp->mb_count - base;
+ *name_lenp = htolel(len);
+
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+ return (error);
+}
+
+/*
+ * Do an SMB1 (old style) rename using a full dest. path.
+ * This is used when renaming to a different directory,
+ * because the (preferred) t2rename can't do that.
+ */
+int
+smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scrp)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = src->n_mount->smi_share;
+ struct mbchain *mbp;
+ int error;
+ uint16_t fa;
+ char sep;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
+ fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
+ fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
+ mb_put_uint16le(mbp, fa);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+
+ /*
+ * When we're not adding any component name, the
+ * passed sep is ignored, so just pass sep=0.
+ */
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
+ if (error)
+ goto out;
+
+ /*
+ * After XATTR directories, separator is ":"
+ */
+ sep = (src->n_flag & N_XATTR) ? ':' : '\\';
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
+ if (error)
+ goto out;
+
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+
+/*
+ * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ */
+static int
+smbfs_smb1_trans2find2(struct smbfs_fctx *ctx)
+{
+ struct smb_t2rq *t2p;
+ struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t ecnt, eos, lno, flags;
+ uint16_t amask, limit;
+ int error;
+
+ /* smbfs_smb_findnextLM2 sets this */
+ limit = ctx->f_limit;
+ amask = (uint16_t)ctx->f_attrmask;
+
+ if (ctx->f_t2) {
+ smb_t2_done(ctx->f_t2);
+ ctx->f_t2 = NULL;
+ }
+ flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
+ flags |= FIND2_CLOSE_AFTER_REQUEST;
+ ctx->f_flags |= SMBFS_RDD_NOCLOSE;
+ }
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
+ ctx->f_scred, &t2p);
+ if (error)
+ return (error);
+ ctx->f_t2 = t2p;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, amask);
+ mb_put_uint16le(mbp, limit);
+ mb_put_uint16le(mbp, flags);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ mb_put_uint32le(mbp, 0);
+ error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
+ ctx->f_wildcard, ctx->f_wclen, '\\');
+ if (error)
+ return (error);
+ } else {
+ error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
+ ctx->f_scred, &t2p);
+ if (error)
+ return (error);
+ ctx->f_t2 = t2p;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, ctx->f_Sid);
+ mb_put_uint16le(mbp, limit);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ /* Send whatever resume key we received... */
+ mb_put_uint32le(mbp, ctx->f_rkey);
+ mb_put_uint16le(mbp, flags);
+ /* ... and the resume name if we have one. */
+ if (ctx->f_rname) {
+ /* resume file name */
+ mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
+ MB_MSYSTEM);
+ }
+ /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+ mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
+ mb_put_uint8(mbp, 0);
+ }
+ t2p->t2_maxpcount = 5 * 2;
+ t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
+ error = smb_t2_request(t2p);
+ if (error)
+ return (error);
+
+ /*
+ * This is the "resume name" we just sent.
+ * We want the new one (if any) that may be
+ * found in the response we just received and
+ * will now begin parsing. Free the old one
+ * now so we'll know if we found a new one.
+ */
+ if (ctx->f_rname) {
+ kmem_free(ctx->f_rname, ctx->f_rnamelen);
+ ctx->f_rname = NULL;
+ ctx->f_rnamelen = 0;
+ }
+
+ mdp = &t2p->t2_rparam;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
+ goto nodata;
+ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
+ }
+ md_get_uint16le(mdp, &ecnt); /* entry count */
+ md_get_uint16le(mdp, &eos); /* end of search */
+ md_get_uint16le(mdp, NULL); /* EA err. off. */
+ error = md_get_uint16le(mdp, &lno); /* last name off. */
+ if (error != 0)
+ goto nodata;
+
+ /*
+ * The "end of search" flag from an XP server sometimes
+ * comes back zero when the prior find_next returned exactly
+ * the number of entries requested. in which case we'd try again
+ * but the search has in fact been closed so an EBADF results.
+ * our circumvention is to check here for a zero entry count.
+ */
+ ctx->f_ecnt = ecnt;
+ if (eos || ctx->f_ecnt == 0)
+ ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
+ if (ctx->f_ecnt == 0)
+ return (ENOENT);
+
+ /* Last Name Off (LNO) is the entry with the resume name. */
+ ctx->f_rnameofs = lno;
+ ctx->f_eofs = 0;
+
+ /*
+ * Have data. Put the payload in ctx->f_mdchain
+ * Note struct assignments here.
+ */
+ mdp = &t2p->t2_rdata;
+ md_done(&ctx->f_mdchain);
+ ctx->f_mdchain = *mdp;
+ ctx->f_left = m_fixhdr(mdp->md_top);
+ bzero(mdp, sizeof (*mdp));
+
+ return (0);
+
+nodata:
+ /*
+ * Failed parsing the FindFirst or FindNext response.
+ * Force this directory listing closed, otherwise the
+ * calling process may hang in an infinite loop.
+ */
+ ctx->f_ecnt = 0; /* Force closed. */
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ return (EIO);
+}
+
+static int
+smbfs_smb1_findclose2(struct smbfs_fctx *ctx)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
+ ctx->f_scred);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, ctx->f_Sid);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ /* Ditto comments at _smb_close */
+ rqp->sr_flags |= SMBR_NOINTR_SEND;
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr)
+{
+
+ ctx->f_type = ft_LM2;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = SMB_FIND_FULL_DIRECTORY_INFO;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+ return (0);
+}
+
+int
+smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
+{
+ int error = 0;
+ if (ctx->f_name)
+ kmem_free(ctx->f_name, ctx->f_namesz);
+ if (ctx->f_t2)
+ smb_t2_done(ctx->f_t2);
+ md_done(&ctx->f_mdchain);
+
+ /*
+ * If SMBFS_RDD_FINDFIRST is still set, we were opened
+ * but never saw a findfirst, so we don't have any
+ * search handle to close.
+ */
+ if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
+ error = smbfs_smb1_findclose2(ctx);
+ return (error);
+}
+
+/*
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
+ */
+int
+smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
+
+ /*
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
+ */
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_smb1_trans2find2(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
+
+ /*
+ * Decode one entry, advance f_eofs
+ */
+ error = smbfs_decode_dirent(ctx);
+
+ return (error);
+}
+
+/*
+ * Helper for smbfs_xa_get_streaminfo
+ * Query stream info
+ */
+int
+smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp)
+{
+ smb_share_t *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_t2rq *t2p = NULL;
+ struct mbchain *mbp;
+ mblk_t *m;
+ uint16_t cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+
+ mbp = &t2p->t2_tparam;
+ (void) mb_init(mbp);
+ (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
+ (void) mb_put_uint32le(mbp, 0);
+ error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, 0);
+ if (error)
+ goto out;
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = INT16_MAX;
+ error = smb_t2_request(t2p);
+ if (error) {
+ if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * Have data. Move it to *mdp
+ */
+ m = t2p->t2_rdata.md_top;
+ if (m == NULL) {
+ error = EBADRPC;
+ goto out;
+ }
+ t2p->t2_rdata.md_top = NULL;
+ md_initm(mdp, m);
+
+out:
+ smb_t2_done(t2p);
+ return (error);
+}
+
+/*
+ * OTW function to Get a security descriptor (SD).
+ *
+ * The *reslen param is bufsize(in) / length(out)
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
+ */
+int
+smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
+{
+ struct smb_ntrq *ntp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t dlen;
+ int error;
+
+ *res = NULL;
+
+ error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
+ scrp, &ntp);
+ if (error)
+ return (error);
+
+ /* Parameters part */
+ mbp = &ntp->nt_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, selector);
+ /* Data part (none) */
+
+ /* Max. returned parameters and data. */
+ ntp->nt_maxpcount = 4;
+ ntp->nt_maxdcount = *reslen; // out buf size
+
+ error = smb_nt_request(ntp);
+ if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
+ goto done;
+
+ /* Get data len */
+ mdp = &ntp->nt_rparam;
+ error = md_get_uint32le(mdp, &dlen);
+ if (error)
+ goto done;
+
+ /*
+ * if there's more data than we said we could receive,
+ * here is where we pick up the length of it
+ */
+ *reslen = dlen;
+ if (dlen == 0) {
+ error = EBADRPC;
+ goto done;
+ }
+
+ /*
+ * get the SD data part.
+ */
+ mdp = &ntp->nt_rdata;
+ error = md_get_mbuf(mdp, dlen, res);
+
+done:
+ if (error == 0 && *res == NULL) {
+ ASSERT(*res);
+ error = EBADRPC;
+ }
+
+ smb_nt_done(ntp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int
+smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
+{
+ struct smb_ntrq *ntp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
+ scrp, &ntp);
+ if (error)
+ return (error);
+
+ /* Parameters part */
+ mbp = &ntp->nt_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, selector);
+
+ /* Data part */
+ mbp = &ntp->nt_tdata;
+ mb_initm(mbp, *mp);
+ *mp = NULL; /* consumed */
+
+ /* No returned parameters or data. */
+ ntp->nt_maxpcount = 0;
+ ntp->nt_maxdcount = 0;
+
+ error = smb_nt_request(ntp);
+ smb_nt_done(ntp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c
new file mode 100644
index 0000000000..80afc327c3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/inttypes.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#if 0 // todo
+
+int
+smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid,
+ offset_t start, uint64_t len, int largelock,
+ struct smb_cred *scrp, uint32_t timeout)
+{
+ return (ENOTSUP);
+}
+
+#endif // todo
+
+/*
+ * Helper for smbfs_getattr_otw
+ * used when we don't have an open FID
+ *
+ * For SMB2 we need to do an attribute-only open. The
+ * data returned by open gets us everything we need, so
+ * just close the handle and we're done.
+ */
+int
+smbfs_smb2_getpattr(
+ struct smbnode *np,
+ struct smbfattr *fap,
+ struct smb_cred *scrp)
+{
+ smb_fh_t tmp_fh;
+ struct smb_share *ssp = np->n_mount->smi_share;
+ uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES);
+ int error;
+
+ bzero(&tmp_fh, sizeof (tmp_fh));
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, &tmp_fh,
+ NULL, fap);
+ if (error == 0) {
+ (void) smb_smb_close(ssp, &tmp_fh, scrp);
+ }
+
+ return (error);
+}
+
+/*
+ * Common SMB2 query file info
+ */
+static int
+smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid,
+ struct mdchain *info_mdp, uint32_t *iolen,
+ uint8_t type, uint8_t level, uint32_t addl_info,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t dlen = 0;
+ uint16_t doff = 0;
+ uint16_t ssize = 0;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp);
+ if (error)
+ goto out;
+
+ /*
+ * Build the SMB 2 Query Info req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 41); // struct size
+ mb_put_uint8(mbp, type);
+ mb_put_uint8(mbp, level);
+ mb_put_uint32le(mbp, *iolen); // out buf len
+ mb_put_uint16le(mbp, 0); // in buf off
+ mb_put_uint16le(mbp, 0); // reserved
+ mb_put_uint32le(mbp, 0); // in buf len
+ mb_put_uint32le(mbp, addl_info);
+ mb_put_uint32le(mbp, 0); // flags
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ error = smb2_rq_simple(rqp);
+ if (error) {
+ if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER)
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * Parse SMB 2 Query Info response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 9 */
+ md_get_uint16le(mdp, &ssize);
+ if (ssize != 9) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ /* Get data off, len */
+ md_get_uint16le(mdp, &doff);
+ md_get_uint32le(mdp, &dlen);
+ *iolen = dlen;
+
+ /*
+ * Skip ahead to the payload, as needed.
+ * Current offset is SMB2_HDRLEN + 8.
+ */
+ if (dlen != 0) {
+ mblk_t *m = NULL;
+ int skip = (int)doff - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ error = md_get_mbuf(mdp, dlen, &m);
+ if (error)
+ goto out;
+ md_initm(info_mdp, m);
+ }
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+
+/*
+ * Get FileAllInformation for an open file
+ * and parse into *fap
+ */
+int
+smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
+ struct smbfattr *fap, struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ uint32_t iolen = 1024;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen,
+ SMB2_0_INFO_FILE, FileAllInformation, 0, scrp);
+ if (error)
+ goto out;
+
+ error = smbfs_decode_file_all_info(ssp, mdp, fap);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get some SMB2_0_INFO_FILESYSTEM info
+ *
+ * Note: This can be called during mount. We don't have any
+ * smbfs_node_t or pathname, so do our own attr. open on
+ * the root of the share to get a handle for this request.
+ */
+static int
+smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp,
+ uint8_t level, struct smb_cred *scrp)
+{
+ smb2fid_t fid;
+ uint32_t iolen = 1024;
+ boolean_t opened = B_FALSE;
+ int error;
+
+ /*
+ * Need a FID for smb2, and this is called during mount
+ * so "go behind" the usual open/close functions.
+ */
+ error = smb2_smb_ntcreate(
+ ssp, NULL, // name
+ NULL, NULL, // create ctx in, out
+ 0, /* NTCREATEX_FLAGS... */
+ SA_RIGHT_FILE_READ_ATTRIBUTES,
+ SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ scrp, &fid, NULL, NULL);
+ if (error != 0)
+ goto out;
+ opened = B_TRUE;
+
+ error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen,
+ SMB2_0_INFO_FILESYSTEM, level, 0, scrp);
+
+out:
+ if (opened)
+ (void) smb2_smb_close(ssp, &fid, scrp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsAttributeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_fs_info(ssp, mdp,
+ FileFsAttributeInformation, scrp);
+ if (error)
+ goto out;
+ error = smbfs_decode_fs_attr_info(ssp, mdp, info);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsFullSizeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb2_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_fs_info(ssp, mdp,
+ FileFsFullSizeInformation, scrp);
+ if (error)
+ goto out;
+
+ md_get_uint64le(mdp, &info->total_units);
+ md_get_uint64le(mdp, &info->caller_avail);
+ md_get_uint64le(mdp, &info->actual_avail);
+
+ md_get_uint32le(mdp, &info->sect_per_unit);
+ error = md_get_uint32le(mdp, &info->bytes_per_sect);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Flush Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 24); /* struct size */
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, 0); /* reserved */
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_simple(rqp);
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+/*
+ * Set file info via an open handle.
+ * Caller provides payload, info level.
+ */
+static int
+smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *info_mbp, uint8_t type, uint8_t level,
+ uint32_t addl_info, struct smb_cred *scrp)
+{
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ uint32_t *buffer_lenp;
+ int base, len;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp);
+ if (error)
+ goto out;
+
+ /*
+ * Build the SMB 2 Set Info req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 33); // struct size
+ mb_put_uint8(mbp, type);
+ mb_put_uint8(mbp, level);
+ buffer_lenp = mb_reserve(mbp, sizeof (uint32_t));
+ mb_put_uint16le(mbp, SMB2_HDRLEN + 32); // Buffer Offset
+ mb_put_uint16le(mbp, 0); // Reserved
+ mb_put_uint32le(mbp, addl_info); // Additional Info
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ /*
+ * Now the payload
+ */
+ base = mbp->mb_count;
+ error = mb_put_mbchain(mbp, info_mbp);
+ if (error)
+ goto out;
+ len = mbp->mb_count - base;
+ *buffer_lenp = htolel(len);
+ if (error)
+ goto out;
+
+ /*
+ * Run the request.
+ * Don't care about the (empty) reply.
+ */
+ error = smb2_rq_simple(rqp);
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid,
+ uint64_t newsize, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint8_t level = FileEndOfFileInformation;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint64le(mbp, newsize);
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ mb_done(mbp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid,
+ uint8_t newdisp, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint8_t level = FileDispositionInformation;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint8(mbp, newdisp);
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Set FileBasicInformation on an open handle
+ * Caller builds the mbchain.
+ */
+int
+smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *mbp, struct smb_cred *scrp)
+{
+ uint8_t level = FileBasicInformation;
+ int error;
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ return (error);
+}
+
+/*
+ * Build a FileRenameInformation and call setinfo
+ */
+int
+smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
+ const char *tname, int tnlen, int overwrite,
+ smb2fid_t *fid, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint32_t *name_lenp;
+ uint8_t level = FileRenameInformation;
+ int base, len;
+ int error;
+
+ mb_init(mbp);
+
+ mb_put_uint32le(mbp, (overwrite & 1));
+ mb_put_uint32le(mbp, 0); // reserved
+ mb_put_uint64le(mbp, 0); // Root Dir
+ name_lenp = mb_reserve(mbp, 4);
+
+ /* Target name (full path) */
+ base = mbp->mb_count;
+ if (tnlen > 0) {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp),
+ tdnp, tname, tnlen, '\\');
+ if (error)
+ goto out;
+ }
+ len = mbp->mb_count - base;
+ *name_lenp = htolel(len);
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+
+out:
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Later servers have maxtransact at a megabyte or more,
+ * but we don't want to buffer up that much data, so use
+ * the lesser of that or 64k.
+ */
+#define SMBFS_QDIR_MAX_BUF (1<<16)
+
+/*
+ * SMB2 query directory
+ */
+static int
+smbfs_smb2_qdir(struct smbfs_fctx *ctx)
+{
+ smb_fh_t *fhp = ctx->f_fhp;
+ smb_share_t *ssp = ctx->f_ssp;
+ smb_vc_t *vcp = SSTOVC(ssp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t *name_lenp;
+ uint8_t level, flags;
+ uint16_t ssize = 0;
+ uint16_t obuf_off = 0;
+ uint32_t obuf_len = 0;
+ uint32_t obuf_req;
+ int error;
+
+ level = (uint8_t)ctx->f_infolevel;
+ flags = 0;
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE)
+ flags |= SMB2_QDIR_FLAG_SINGLE;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST)
+ ctx->f_rkey = 0;
+ else
+ flags |= SMB2_QDIR_FLAG_INDEX;
+
+ obuf_req = SMBFS_QDIR_MAX_BUF;
+ if (obuf_req > vcp->vc_sopt.sv2_maxtransact)
+ obuf_req = vcp->vc_sopt.sv2_maxtransact;
+
+ if (ctx->f_rq) {
+ smb_rq_done(ctx->f_rq);
+ ctx->f_rq = NULL;
+ }
+ error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY,
+ ctx->f_scred, &rqp);
+ if (error)
+ return (error);
+ ctx->f_rq = rqp;
+
+ /*
+ * Build an SMB2 Query Dir req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+
+ mb_put_uint16le(mbp, 33); /* Struct size */
+ mb_put_uint8(mbp, level);
+ mb_put_uint8(mbp, flags);
+ mb_put_uint32le(mbp, ctx->f_rkey); /* FileIndex */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint16le(mbp, 96);
+ name_lenp = mb_reserve(mbp, sizeof (uint16_t)); /* FileNameLen */
+ mb_put_uint32le(mbp, obuf_req); /* Output Buf Len */
+
+ /* Add in the name if any */
+ if (ctx->f_wclen > 0) {
+ int base, len;
+
+ /* Put the match pattern. */
+ base = mbp->mb_count;
+ error = smb_put_dmem(mbp, vcp,
+ ctx->f_wildcard, ctx->f_wclen,
+ SMB_CS_NONE, NULL);
+ if (error)
+ return (error);
+
+ /* Update the FileNameLen */
+ len = mbp->mb_count - base;
+ *name_lenp = htoles(len);
+ } else {
+ /* Empty string */
+ mb_put_uint16le(mbp, 0);
+ *name_lenp = 0;
+ }
+
+ error = smb2_rq_simple(rqp);
+ if (error != 0)
+ goto out;
+
+ /*
+ * Parse the SMB2 Query Dir response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 9 */
+ md_get_uint16le(mdp, &ssize);
+ if (ssize != 9) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ /* Get output buffer offset, length */
+ md_get_uint16le(mdp, &obuf_off);
+ md_get_uint32le(mdp, &obuf_len);
+
+ /*
+ * After read at EOF we'll have just one word:
+ * NextEntryOffset == 0 Allow some padding.
+ */
+ if (obuf_len < 8) {
+ error = ENOENT;
+ goto out;
+ }
+
+ /*
+ * If this reply is shorter than requested by 1k
+ * or more, we must have reached EOF.
+ */
+ if ((obuf_len + 1024) < obuf_req)
+ ctx->f_flags |= SMBFS_RDD_EOF;
+
+ /*
+ * Have data. Put the payload in ctx->f_mdchain
+ * Current offset is SMB2_HDRLEN + 8.
+ */
+ {
+ mblk_t *m = NULL;
+ int skip = (int)obuf_off - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ error = md_get_mbuf(mdp, obuf_len, &m);
+ if (error)
+ goto out;
+ md_done(&ctx->f_mdchain);
+ md_initm(&ctx->f_mdchain, m);
+ }
+
+ /*
+ * SMB2 Query Directory does not provie an EntryCount.
+ * Instead, we'll advance f_eofs (entry offset)
+ * through the range [0..f_left]
+ */
+ ctx->f_left = obuf_len;
+ ctx->f_eofs = 0;
+ return (0);
+
+out:
+ if (error != 0) {
+ /*
+ * Failed parsing the FindFirst or FindNext response.
+ * Force this directory listing closed, otherwise the
+ * calling process may hang in an infinite loop.
+ */
+ ctx->f_left = 0;
+ ctx->f_eofs = 0;
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ }
+
+ return (error);
+}
+
+int
+smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr)
+{
+ smb_fh_t *fhp = NULL;
+ uint32_t rights =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES |
+ SA_RIGHT_FILE_READ_DATA;
+ int error;
+
+ /*
+ * Set f_type no matter what, so cleanup will call
+ * smbfs_smb2_findclose, error or not.
+ */
+ ctx->f_type = ft_SMB2;
+ ASSERT(ctx->f_dnp == dnp);
+
+ /*
+ * Get a file handle on the directory
+ */
+ error = smb_fh_create(ctx->f_ssp, &fhp);
+ if (error != 0)
+ goto errout;
+
+ error = smbfs_smb_ntcreatex(dnp,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ ctx->f_scred, fhp,
+ NULL, NULL); /* cr_act_p fa_p */
+ if (error != 0)
+ goto errout;
+
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ ctx->f_fhp = fhp;
+
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = FileFullDirectoryInformation;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+
+ return (0);
+
+errout:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+ return (error);
+}
+
+int
+smbfs_smb2_findclose(struct smbfs_fctx *ctx)
+{
+ smb_fh_t *fhp = NULL;
+
+ if ((fhp = ctx->f_fhp) != NULL) {
+ ctx->f_fhp = NULL;
+ smb_fh_rele(fhp);
+ }
+ if (ctx->f_name)
+ kmem_free(ctx->f_name, ctx->f_namesz);
+ if (ctx->f_rq)
+ smb_rq_done(ctx->f_rq);
+ md_done(&ctx->f_mdchain);
+
+ return (0);
+}
+
+/*
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
+ */
+int
+smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
+
+ /*
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
+ */
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_smb2_qdir(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
+
+ /*
+ * Decode one entry
+ */
+ error = smbfs_decode_dirent(ctx);
+
+ return (error);
+}
+
+
+/*
+ * Helper for smbfs_xa_get_streaminfo
+ * Query stream info
+ */
+int
+smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp)
+{
+ smb_share_t *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp = NULL;
+ uint32_t rights =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES;
+ uint32_t iolen = INT16_MAX;
+ int error;
+
+ /*
+ * Get a file handle on the object
+ * with read attr. rights.
+ */
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp, NULL, NULL);
+ if (error != 0)
+ goto out;
+
+ smb_fh_opened(fhp);
+
+ /*
+ * Query stream info
+ */
+ error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen,
+ SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp);
+
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Get a security descriptor (SD).
+ *
+ * The *reslen param is bufsize(in) / length(out)
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
+ */
+int
+smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_info(ssp, fid, mdp, reslen,
+ SMB2_0_INFO_SECURITY, 0, selector, scrp);
+ if (error)
+ goto out;
+
+ if (mdp->md_top == NULL) {
+ error = EBADRPC;
+ goto out;
+ }
+ *res = mdp->md_top;
+ mdp->md_top = NULL;
+
+out:
+ md_done(mdp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int
+smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
+{
+ struct mbchain info_mbp, *mbp = &info_mbp;
+ int error;
+
+ ASSERT(*mp != NULL);
+ mb_initm(mbp, *mp);
+ *mp = NULL; /* consumed */
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_SECURITY, 0, selector, scrp);
+
+ mb_done(mbp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
index 71d49c49b4..0b5eb411f1 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -47,6 +48,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -73,10 +75,11 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
int error;
- if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
- caseopt |= SMB_CS_UPPER;
-
- if (unicode) {
+ /*
+ * SMB1 may need an alignment pad before (not SMB2)
+ */
+ if (((vcp)->vc_flags & SMBV_SMB2) == 0 &&
+ ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) {
error = mb_put_padbyte(mbp);
if (error)
return (error);
@@ -122,11 +125,14 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
if (error)
return (error);
}
- /* Put NULL termination. */
- if (unicode)
- error = mb_put_uint16le(mbp, 0);
- else
- error = mb_put_uint8(mbp, 0);
+
+ /* SMB1 wants NULL termination. */
+ if (((vcp)->vc_flags & SMBV_SMB2) == 0) {
+ if (unicode)
+ error = mb_put_uint16le(mbp, 0);
+ else
+ error = mb_put_uint8(mbp, 0);
+ }
return (error);
}
@@ -183,3 +189,271 @@ errout:
*/
(void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
}
+
+/*
+ * Decode a directory entry from OtW form into ctx->f_attr
+ *
+ * Caller already put some (wire-format) directory entries
+ * into ctx->f_mdchain and we expect to find one.
+ *
+ * Advancing correctly through the buffer can be tricky if one
+ * tries to add up the size of an entry as you go (which is how
+ * the darwin code this is derived from did it). The easiest way
+ * to correctly advance the position is to get a whole dirent
+ * into another mdchain (entry_mdc) based on NextEntryOffset,
+ * and then scan the data from that mdchain. On the last entry,
+ * we don't know the entire length, so just scan directly from
+ * what remains of the multi-entry buffer instead of trying to
+ * figure out the length to copy into a separate mdchain.
+ */
+int
+smbfs_decode_dirent(struct smbfs_fctx *ctx)
+{
+ struct mdchain entry_mdc;
+ struct mdchain *mdp = &ctx->f_mdchain;
+ size_t nmlen;
+ uint64_t llongint;
+ uint32_t nmsize, dattr;
+ uint32_t nextoff = 0;
+ int error;
+
+ /* In case we error out... */
+ ctx->f_nmlen = 0;
+ ctx->f_rkey = (uint32_t)-1;
+ bzero(&entry_mdc, sizeof (entry_mdc));
+
+ /*
+ * Setup mdp to point to an mbchain holding
+ * what should be a single directory entry.
+ */
+ error = md_get_uint32le(mdp, &nextoff);
+ if (error != 0)
+ goto errout;
+ if (nextoff >= 4) {
+ /*
+ * More entries follow. Make a new mbchain
+ * holding just this one entry, then advance.
+ */
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, nextoff - 4, &m);
+ if (error != 0)
+ goto errout;
+ md_initm(&entry_mdc, m);
+ mdp = &entry_mdc;
+ ctx->f_eofs += nextoff;
+ } else {
+ /* Scan directly from ctx->f_mdchain */
+ ctx->f_eofs = ctx->f_left;
+ }
+
+ /*
+ * Decode the fixed-size parts
+ */
+ switch (ctx->f_infolevel) {
+ case FileFullDirectoryInformation:
+ case SMB_FIND_FULL_DIRECTORY_INFO:
+ md_get_uint32le(mdp, &ctx->f_rkey); /* resume key (idx) */
+ md_get_uint64le(mdp, &llongint); /* creation time */
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
+ md_get_uint64le(mdp, &llongint); /* file size */
+ ctx->f_attr.fa_size = llongint;
+ md_get_uint64le(mdp, &llongint); /* alloc. size */
+ ctx->f_attr.fa_allocsz = llongint;
+ md_get_uint32le(mdp, &dattr); /* ext. file attributes */
+ ctx->f_attr.fa_attr = dattr;
+ error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */
+ if (error)
+ goto errout;
+ md_get_uint32le(mdp, NULL); /* Ea size */
+ break;
+
+ case FileStreamInformation:
+ error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */
+ md_get_uint64le(mdp, &llongint); /* file size */
+ ctx->f_attr.fa_size = llongint;
+ md_get_uint64le(mdp, &llongint); /* alloc. size */
+ ctx->f_attr.fa_allocsz = llongint;
+ /*
+ * Stream names start with a ':' that we want to skip.
+ * This is the easiest place to take care of that.
+ * Always unicode here.
+ */
+ if (nmsize >= 2) {
+ struct mdchain save_mdc;
+ uint16_t wch;
+ save_mdc = *mdp;
+ md_get_uint16le(mdp, &wch);
+ if (wch == ':') {
+ /* OK, we skipped the ':' */
+ nmsize -= 2;
+ } else {
+ SMBVDEBUG("No leading : in stream?\n");
+ /* restore position */
+ *mdp = save_mdc;
+ }
+ }
+ break;
+
+ default:
+ SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
+ error = EINVAL;
+ goto errout;
+ }
+
+ /*
+ * Get the filename, and convert to utf-8
+ * Allocated f_name in findopen
+ */
+ nmlen = ctx->f_namesz;
+ error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp),
+ ctx->f_name, &nmlen, nmsize);
+ if (error != 0)
+ goto errout;
+ ctx->f_nmlen = (int)nmlen;
+ md_done(&entry_mdc);
+ return (0);
+
+errout:
+ /*
+ * Something bad has happened and we ran out of data
+ * before we could parse all f_ecnt entries expected.
+ * Give up on the current buffer.
+ */
+ SMBVDEBUG("ran out of data\n");
+ ctx->f_eofs = ctx->f_left;
+ md_done(&entry_mdc);
+ return (error);
+}
+
+/*
+ * Decode FileAllInformation
+ *
+ * The data is a concatenation of:
+ * FileBasicInformation
+ * FileStandardInformation
+ * FileInternalInformation
+ * FileEaInformation
+ * FilePositionInformation
+ * FileModeInformation
+ * FileAlignmentInformation
+ * FileNameInformation
+ */
+/*ARGSUSED*/
+int
+smbfs_decode_file_all_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smbfattr *fap)
+{
+ uint64_t llongint, lsize;
+ uint32_t dattr;
+ int error;
+
+ /*
+ * This part is: FileBasicInformation
+ */
+
+ /* creation time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_createtime);
+
+ /* last access time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_atime);
+
+ /* last write time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_mtime);
+
+ /* last change time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_ctime);
+
+ /* attributes */
+ md_get_uint32le(mdp, &dattr);
+ fap->fa_attr = dattr;
+
+ /* reserved */
+ md_get_uint32le(mdp, NULL);
+
+ /*
+ * This part is: FileStandardInformation
+ */
+
+ /* allocation size */
+ md_get_uint64le(mdp, &lsize);
+ fap->fa_allocsz = lsize;
+
+ /* File size */
+ error = md_get_uint64le(mdp, &lsize);
+ fap->fa_size = lsize;
+
+ /*
+ * There's more after this but we don't need it:
+ * Remainder of FileStandardInformation
+ * NumLlinks, DeletOnClose, IsDir, reserved.
+ * Then:
+ * FileInternalInformation
+ * FileEaInformation
+ * FilePositionInformation
+ * FileModeInformation
+ * FileAlignmentInformation
+ * FileNameInformation
+ */
+
+ return (error);
+}
+
+/*
+ * Decode FileFsAttributeInformation
+ *
+ * ULONG FileSystemAttributes;
+ * LONG MaximumComponentNameLength;
+ * ULONG FileSystemNameLength;
+ * WCHAR FileSystemName[1];
+ */
+int
+smbfs_decode_fs_attr_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smb_fs_attr_info *fsa)
+{
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t nlen;
+ int error;
+
+ md_get_uint32le(mdp, &fsa->fsa_aflags);
+ md_get_uint32le(mdp, &fsa->fsa_maxname);
+ error = md_get_uint32le(mdp, &nlen); /* fs name length */
+ if (error)
+ goto out;
+
+ /*
+ * Get the FS type name.
+ */
+ bzero(fsa->fsa_tname, FSTYPSZ);
+ if (SMB_UNICODE_STRINGS(vcp)) {
+ uint16_t tmpbuf[FSTYPSZ];
+ size_t tmplen, outlen;
+
+ if (nlen > sizeof (tmpbuf))
+ nlen = sizeof (tmpbuf);
+ error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
+ if (error != 0)
+ goto out;
+ tmplen = nlen / 2; /* UCS-2 chars */
+ outlen = FSTYPSZ - 1;
+ error = uconv_u16tou8(tmpbuf, &tmplen,
+ (uchar_t *)fsa->fsa_tname, &outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ } else {
+ if (nlen > (FSTYPSZ - 1))
+ nlen = FSTYPSZ - 1;
+ error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
+ }
+
+out:
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
index fc7a4ffa26..f8d708b5a3 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _FS_SMBFS_SMBFS_SUBR_H_
@@ -85,6 +86,7 @@ struct timespec;
typedef enum {
ft_LM1 = 1,
ft_LM2,
+ ft_SMB2,
ft_XA
} smbfs_fctx_type_t;
@@ -120,31 +122,33 @@ struct smbfs_fctx {
/*
* Internal variables
*/
+ uint16_t f_infolevel;
uint16_t f_limit; /* maximum number of entries */
- uint16_t f_attrmask; /* SMB_FA_ */
+ uint32_t f_attrmask; /* SMB_FA_ */
int f_wclen;
const char *f_wildcard;
struct smbnode *f_dnp;
struct smb_cred *f_scred;
struct smb_share *f_ssp;
+ struct smb_fh *f_fhp;
union {
struct smb_rq *uf_rq;
struct smb_t2rq *uf_t2;
- } f_urq;
+ } f_urq; // XXX remove and use...
+ struct mdchain f_mdchain;
int f_left; /* entries left */
int f_ecnt; /* entries left in current response */
int f_eofs; /* entry offset in data block */
uchar_t f_skey[SMB_SKEYLEN]; /* server side search context */
uchar_t f_fname[8 + 1 + 3 + 1]; /* for 8.3 filenames */
uint16_t f_Sid; /* Search handle (like a FID) */
- uint16_t f_infolevel;
int f_rnamelen;
char *f_rname; /* resume name */
int f_rnameofs;
int f_otws; /* # over-the-wire ops so far */
char *f_firstnm; /* first filename we got back */
int f_firstnmlen;
- int f_rkey; /* resume key */
+ uint32_t f_rkey; /* resume key */
};
typedef struct smbfs_fctx smbfs_fctx_t;
@@ -152,73 +156,163 @@ typedef struct smbfs_fctx smbfs_fctx_t;
#define f_t2 f_urq.uf_t2
/*
- * smb level (smbfs_smb.c)
+ * Internal form of FileFsFullSizeInformation
+ * [MS-FSCC] 2.5.4 FileFsFullSizeInformation
+ * for the _statfs functions.
+ */
+struct smb_fs_size_info {
+ uint64_t total_units;
+ uint64_t caller_avail;
+ uint64_t actual_avail;
+ uint32_t sect_per_unit;
+ uint32_t bytes_per_sect;
+};
+
+/*
+ * smb common functions (smbfs_smbx.c)
*/
int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
offset_t start, uint64_t len, int largelock,
struct smb_cred *scrp, uint32_t timeout);
+int smbfs_smb_getfattr(struct smbnode *np, smb_fh_t *fhp,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb_getpattr(struct smbnode *np, struct smbfattr *fap,
+ struct smb_cred *scrp);
int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
struct smb_cred *scrp);
int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scrp);
-
-int smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp,
- struct smb_cred *scrp);
-int smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
+int smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fid, uint8_t newdisp,
struct smb_cred *scrp);
-
-int smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap,
+int smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fid, uint64_t newsize,
struct smb_cred *scrp);
-
-int smbfs_smb_setfattr(struct smbnode *np, int fid,
+int smbfs_smb_setfattr(struct smb_share *ssp, smb_fh_t *fid,
uint32_t attr, struct timespec *mtime, struct timespec *atime,
struct smb_cred *scrp);
+int smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fid,
+ struct smb_cred *scrp);
+
+int smbfs_smb_ntcreatex(
+ struct smbnode *np, const char *name, int nmlen, int xattr,
+ uint32_t req_acc, uint32_t efa, uint32_t share_acc,
+ uint32_t disp, uint32_t createopt, struct smb_cred *scrp,
+ smb_fh_t *fhpp, uint32_t *cr_act_p, struct smbfattr *fap);
+int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
+ struct smb_cred *scrp, smb_fh_t **fidpp);
+void smbfs_smb_tmpclose(struct smbnode *ssp, smb_fh_t *fid);
int smbfs_smb_open(struct smbnode *np, const char *name, int nmlen,
int xattr, uint32_t rights, struct smb_cred *scrp,
- uint16_t *fidp, uint32_t *rightsp, struct smbfattr *fap);
-int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
- struct smb_cred *scrp, uint16_t *fidp);
-int smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
- struct timespec *mtime, struct smb_cred *scrp);
-int smbfs_smb_tmpclose(struct smbnode *ssp, uint16_t fid,
- struct smb_cred *scrp);
+ smb_fh_t **fidpp, struct smbfattr *fap);
+void smbfs_smb_close(smb_fh_t *fid);
int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, uint32_t disp, struct smb_cred *scrp, uint16_t *fidp);
-int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp,
- const char *name, int len, int xattr);
-int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp);
-int smbfs_smb_t2rename(struct smbnode *np, const char *tname, int tnmlen,
- struct smb_cred *scrp, uint16_t fid, int replace);
-int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp);
+ int xattr, uint32_t disp, struct smb_cred *scrp, smb_fh_t **fidpp);
+int smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *src,
+ struct smbnode *tdnp, const char *tname, int tnmlen,
+ smb_fh_t *fid, struct smb_cred *scrp);
int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
struct smb_cred *scrp);
-int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp);
+
int smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp);
int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit,
struct smb_cred *scrp);
int smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp);
-int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
- struct smbnode *dnp, const char *name, int nmlen, uint8_t sep);
+
int smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
struct smbfattr *fap, struct smb_cred *scrp);
-int smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp);
-int smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp);
-int smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp);
-int smbfs_0extend(vnode_t *vp, uint16_t fid, len_t from, len_t to,
- struct smb_cred *scredp, int timo);
/* get/set security descriptor */
-int smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector,
- mblk_t **res, uint32_t *reslen);
-int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector, mblk_t **mp);
+int smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp);
+
+/*
+ * SMB1 functions
+ */
+int smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
+ struct smb_cred *scrp);
+int smbfs_smb1_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info, struct smb_cred *scrp);
+int smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
+ struct smb_cred *scrp);
+int smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid, uint8_t newdisp,
+ struct smb_cred *scrp);
+int smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *, struct smb_cred *);
+int smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid,
+ struct smb_cred *scrp);
+int smbfs_smb1_t2rename(struct smbnode *np, const char *tname, int tnmlen,
+ uint16_t fid, struct smb_cred *scrp);
+int smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scrp);
+
+int smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr);
+int smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit);
+int smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx);
+int smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp);
+
+int smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp);
+
+/*
+ * SMB2 functions
+ */
+
+int smbfs_smb2_getpattr(struct smbnode *np, struct smbfattr *fap,
+ struct smb_cred *scrp);
+int smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
+ struct smb_cred *scrp);
+int smbfs_smb2_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info, struct smb_cred *scrp);
+int smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid, uint64_t newsize,
+ struct smb_cred *scrp);
+int smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid, uint8_t newdisp,
+ struct smb_cred *scrp);
+int smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp);
+int smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *, struct smb_cred *);
+int smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
+ const char *tname, int tnlen, int overwrite,
+ smb2fid_t *fid, struct smb_cred *scrp);
+
+int smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr);
+int smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit);
+int smbfs_smb2_findclose(struct smbfs_fctx *ctx);
+int smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp);
+
+int smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp);
+
+
+/* smbfs_subr.c */
+
+int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
+ struct smbnode *dnp, const char *name, int nmlen, uint8_t sep);
+int smbfs_decode_dirent(struct smbfs_fctx *ctx);
+int smbfs_decode_file_all_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smbfattr *fap);
+int smbfs_decode_fs_attr_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smb_fs_attr_info *fsa);
/*
* VFS-level init, fini stuff
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
index 798c26a09b..768664b610 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
@@ -27,6 +27,7 @@
*/
/*
* Copyright (c) 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -39,7 +40,9 @@
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/vnode.h>
+#include <sys/atomic.h>
#include <sys/bitmap.h>
+#include <sys/buf.h>
#include <sys/dnlc.h>
#include <sys/kmem.h>
#include <sys/sunddi.h>
@@ -430,7 +433,7 @@ start:
np->r_vnode = vp;
np->n_mount = mi;
- np->n_fid = SMB_FID_UNUSED;
+ np->n_fid = NULL;
np->n_uid = mi->smi_uid;
np->n_gid = mi->smi_gid;
/* Leave attributes "stale." */
@@ -1231,7 +1234,7 @@ smbfs_subrinit(void)
nsmbnode_max = (ulong_t)((kmem_maxavail() >> 2) /
sizeof (struct smbnode));
if (nsmbnode > nsmbnode_max || (nsmbnode == 0 && ncsize == 0)) {
- zcmn_err(GLOBAL_ZONEID, CE_NOTE,
+ cmn_err(CE_NOTE,
"setting nsmbnode to max value of %ld", nsmbnode_max);
nsmbnode = nsmbnode_max;
}
@@ -1249,7 +1252,7 @@ smbfs_subrinit(void)
* Assign unique major number for all smbfs mounts
*/
if ((smbfs_major = getudev()) == -1) {
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfs: init: can't get unique device number");
smbfs_major = 0;
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
index 0122d52115..7dad8d2a70 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
@@ -34,9 +34,9 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/systm.h>
@@ -76,6 +76,17 @@
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
+#ifndef _KERNEL
+
+#include <libfksmbfs.h>
+
+#define STRUCT_DECL(s, a) struct s a
+#define STRUCT_FGET(handle, field) ((handle).field)
+#define _init(v) fksmbfs_init(v)
+#define _fini(v) fksmbfs_fini(v)
+
+#endif /* !_KERNEL */
+
/*
* Should smbfs mount enable "-o acl" by default? There are good
* arguments for both. The most common use case is individual users
@@ -98,7 +109,10 @@ int smbfs_tq_nthread = 1;
*/
int smbfsinit(int fstyp, char *name);
void smbfsfini();
+
+#ifdef _KERNEL
static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *);
+#endif /* _KERNEL */
/*
* SMBFS Mount options table for MS_OPTIONSTR
@@ -123,7 +137,11 @@ static mntopt_t mntopts[] = {
{ MNTOPT_ACL, acl_cancel, NULL, 0, 0 },
{ MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 },
{ MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 },
- { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 }
+ { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 },
+#ifndef _KERNEL
+ /* See vfs_optionisset MNTOPT_NOAC below. */
+ { MNTOPT_NOAC, NULL, NULL, 0, 0 },
+#endif /* !_KERNEL */
};
static mntopts_t smbfs_mntopts = {
@@ -141,6 +159,7 @@ static vfsdef_t vfw = {
&smbfs_mntopts /* mount options table prototype */
};
+#ifdef _KERNEL
static struct modlfs modlfs = {
&mod_fsops,
"SMBFS filesystem",
@@ -150,6 +169,7 @@ static struct modlfs modlfs = {
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlfs, NULL
};
+#endif /* _KERNEL */
/*
* Mutex to protect the following variables:
@@ -222,7 +242,12 @@ _init(void)
return (error);
}
+#ifdef _KERNEL
error = mod_install((struct modlinkage *)&modlinkage);
+#else /* _KERNEL */
+ error = fake_installfs(&vfw);
+#endif /* _KERNEL */
+
return (error);
}
@@ -244,7 +269,11 @@ _fini(void)
if (smbfs_mountcount)
return (EBUSY);
+#ifdef _KERNEL
error = mod_remove(&modlinkage);
+#else /* _KERNEL */
+ error = fake_removefs(&vfw);
+#endif /* _KERNEL */
if (error)
return (error);
@@ -267,17 +296,19 @@ _fini(void)
/*
* Return information about the module
*/
+#ifdef _KERNEL
int
_info(struct modinfo *modinfop)
{
return (mod_info((struct modlinkage *)&modlinkage, modinfop));
}
+#endif /* _KERNEL */
/*
* Initialize the vfs structure
*/
-int smbfsfstyp;
+int smbfs_fstyp;
vfsops_t *smbfs_vfsops = NULL;
static const fs_operation_def_t smbfs_vfsops_template[] = {
@@ -292,6 +323,10 @@ static const fs_operation_def_t smbfs_vfsops_template[] = {
{ NULL, NULL }
};
+/*
+ * This is the VFS switch initialization routine, normally called
+ * via vfssw[x].vsw_init by vfsinit() or mod_install
+ */
int
smbfsinit(int fstyp, char *name)
{
@@ -299,7 +334,7 @@ smbfsinit(int fstyp, char *name)
error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
if (error != 0) {
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfsinit: bad vfs ops template");
return (error);
}
@@ -307,12 +342,12 @@ smbfsinit(int fstyp, char *name)
error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
if (error != 0) {
(void) vfs_freevfsops_by_type(fstyp);
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfsinit: bad vnode ops template");
return (error);
}
- smbfsfstyp = fstyp;
+ smbfs_fstyp = fstyp;
return (0);
}
@@ -321,7 +356,7 @@ void
smbfsfini()
{
if (smbfs_vfsops) {
- (void) vfs_freevfsops_by_type(smbfsfstyp);
+ (void) vfs_freevfsops_by_type(smbfs_fstyp);
smbfs_vfsops = NULL;
}
if (smbfs_vnodeops) {
@@ -336,8 +371,10 @@ smbfs_free_smi(smbmntinfo_t *smi)
if (smi == NULL)
return;
+#ifdef _KERNEL
if (smi->smi_zone_ref.zref_zone != NULL)
zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS);
+#endif /* _KERNEL */
if (smi->smi_share != NULL)
smb_share_rele(smi->smi_share);
@@ -364,16 +401,21 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
dev_t smbfs_dev;
int version;
int devfd;
- zone_t *zone = curproc->p_zone;
+ zone_t *zone = curzone;
+#ifdef _KERNEL
zone_t *mntzone = NULL;
+#else /* _KERNEL */
+ short minclsyspri = MINCLSYSPRI;
+#endif /* _KERNEL */
smb_share_t *ssp = NULL;
smb_cred_t scred;
int flags, sec;
-
STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */
+#ifdef _KERNEL
if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
return (error);
+#endif /* _KERNEL */
if (mvp->v_type != VDIR)
return (ENOTDIR);
@@ -384,11 +426,17 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* uap->datalen might be different from sizeof (args)
* in a compatible situation.
*/
+#ifdef _KERNEL
STRUCT_INIT(args, get_udatamodel());
bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE));
if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE))))
return (EFAULT);
+#else /* _KERNEL */
+ bzero(&args, sizeof (args));
+ if (copyin(data, &args, MIN(uap->datalen, sizeof (args))))
+ return (EFAULT);
+#endif /* _KERNEL */
/*
* Check mount program version
@@ -439,6 +487,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* See: ssp, smi, rtnp, mntzone
*/
+#ifdef _KERNEL
/*
* Determine the zone we're being mounted into.
*/
@@ -482,6 +531,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
}
}
+#endif /* _KERNEL */
/* Prevent unload. */
atomic_inc_32(&smbfs_mountcount);
@@ -504,6 +554,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
smi->smi_share = ssp;
ssp = NULL;
+#ifdef _KERNEL
/*
* Convert the anonymous zone hold acquired via zone_hold() above
* into a zone reference.
@@ -512,15 +563,22 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS);
zone_rele(mntzone);
mntzone = NULL;
+#else /* _KERNEL */
+ smi->smi_zone_ref.zref_zone = curzone;
+#endif /* _KERNEL */
/*
* Initialize option defaults
*/
- smi->smi_flags = SMI_LLOCK;
smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN);
smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX);
smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN);
smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX);
+ smi->smi_flags = SMI_LLOCK;
+#ifndef _KERNEL
+ /* Always direct IO with fakekernel */
+ smi->smi_flags |= SMI_DIRECTIO;
+#endif /* _KERNEL */
/*
* All "generic" mount options have already been
@@ -541,10 +599,30 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* starting with args.flags (SMBFS_MF_xxx)
*/
flags = STRUCT_FGET(args, flags);
- smi->smi_uid = STRUCT_FGET(args, uid);
- smi->smi_gid = STRUCT_FGET(args, gid);
smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777;
smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777;
+#ifdef _KERNEL
+ smi->smi_uid = STRUCT_FGET(args, uid);
+ smi->smi_gid = STRUCT_FGET(args, gid);
+#else /* _KERNEL */
+ /*
+ * Need uid/gid to match our fake cred we'll fail in
+ * smbfs_access_rwx later.
+ */
+ smi->smi_uid = crgetuid(cr);
+ smi->smi_gid = crgetgid(cr);
+
+ /*
+ * Our user-level do_mount() passes the mount options sting
+ * as-is, where the real mount program would convert some
+ * of those options to bits set in smbfs_args.flags.
+ * To avoid replicating all that conversion code, this
+ * uses the generic vfs option support to handle those
+ * option flag bits we need, i.e.: "noac"
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_NOAC, NULL))
+ flags |= SMBFS_MF_NOAC;
+#endif /* _KERNEL */
/*
* Hande the SMBFS_MF_xxx flags.
@@ -615,9 +693,9 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
mutex_exit(&smbfs_minor_lock);
vfsp->vfs_dev = smbfs_dev;
- vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp);
+ vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfs_fstyp);
vfsp->vfs_data = (caddr_t)smi;
- vfsp->vfs_fstype = smbfsfstyp;
+ vfsp->vfs_fstype = smbfs_fstyp;
vfsp->vfs_bsize = MAXBSIZE;
vfsp->vfs_bcount = 0;
@@ -657,6 +735,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
*/
return (0);
+#ifdef _KERNEL
errout:
vfsp->vfs_data = NULL;
if (smi != NULL)
@@ -669,6 +748,7 @@ errout:
smb_share_rele(ssp);
return (error);
+#endif /* _KERNEL */
}
/*
@@ -682,8 +762,10 @@ smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
smi = VFTOSMI(vfsp);
+#ifdef _KERNEL
if (secpolicy_fs_unmount(cr, vfsp) != 0)
return (EPERM);
+#endif /* _KERNEL */
if ((flag & MS_FORCE) == 0) {
smbfs_rflush(vfsp, cr);
@@ -976,6 +1058,7 @@ smbfs_freevfs(vfs_t *vfsp)
atomic_dec_32(&smbfs_mountcount);
}
+#ifdef _KERNEL
/*
* smbfs_mount_label_policy:
* Determine whether the mount is allowed according to MAC check,
@@ -1066,3 +1149,4 @@ out:
label_rele(zlabel);
return (retv);
}
+#endif /* _KERNEL */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
index 23c9f8f15d..3fca806155 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -60,8 +61,9 @@
#include <sys/sdt.h>
#include <sys/taskq_impl.h>
#include <sys/zone.h>
-#include <sys/vmsystm.h>
+#ifdef _KERNEL
+#include <sys/vmsystm.h> // for desfree
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/page.h>
@@ -70,6 +72,7 @@
#include <vm/seg_map.h>
#include <vm/seg_kpm.h>
#include <vm/seg_vn.h>
+#endif // _KERNEL
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
@@ -83,6 +86,10 @@
#include <sys/fs/smbfs_ioctl.h>
#include <fs/fs_subr.h>
+#ifndef MAXOFF32_T
+#define MAXOFF32_T 0x7fffffff
+#endif
+
/*
* We assign directory offsets like the NFS client, where the
* offset increments by _one_ after each directory entry.
@@ -137,18 +144,15 @@ static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
static int smbfs_accessx(void *, int, cred_t *);
static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
caller_context_t *);
+static int smbfsflush(smbnode_t *, struct smb_cred *);
static void smbfs_rele_fid(smbnode_t *, struct smb_cred *);
static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
-static int smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static int smbfs_bio(struct buf *, int, cred_t *);
-static int smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
- struct uio *uiop, int pgcreated);
-
static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+
static int smbfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
caller_context_t *);
+#ifdef _KERNEL
static int smbfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
@@ -156,6 +160,13 @@ static int smbfs_putapage(vnode_t *, page_t *, u_offset_t *, size_t *,
int, cred_t *);
static void smbfs_delmap_async(void *);
+static int smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
+ cred_t *);
+static int smbfs_bio(struct buf *, int, cred_t *);
+static int smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
+ struct uio *uiop, int pgcreated);
+#endif // _KERNEL
+
/*
* Error flags used to pass information about certain special errors
* which need to be handled specially.
@@ -191,14 +202,13 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
smbnode_t *np;
vnode_t *vp;
smbfattr_t fa;
- u_int32_t rights, rightsrcvd;
- u_int16_t fid, oldfid;
- int oldgenid;
+ smb_fh_t *fid = NULL;
+ smb_fh_t *oldfid;
+ uint32_t rights;
struct smb_cred scred;
smbmntinfo_t *smi;
smb_share_t *ssp;
cred_t *oldcr;
- int tmperror;
int error = 0;
vp = *vpp;
@@ -270,14 +280,15 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* check whether the rights are sufficient for FID reuse.
*/
if (np->n_fidrefs > 0 &&
- np->n_vcgenid == ssp->ss_vcgenid) {
+ (fid = np->n_fid) != NULL &&
+ fid->fh_vcgenid == ssp->ss_vcgenid) {
int upgrade = 0;
if ((flag & FWRITE) &&
- !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
+ !(fid->fh_rights & SA_RIGHT_FILE_WRITE_DATA))
upgrade = 1;
if ((flag & FREAD) &&
- !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
+ !(fid->fh_rights & SA_RIGHT_FILE_READ_DATA))
upgrade = 1;
if (!upgrade) {
/*
@@ -286,8 +297,9 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
np->n_fidrefs++;
goto have_fid;
}
+ fid = NULL;
}
- rights = np->n_fidrefs ? np->n_rights : 0;
+ rights = (fid != NULL) ? fid->fh_rights : 0;
/*
* we always ask for READ_CONTROL so we can always get the
@@ -306,7 +318,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
error = smbfs_smb_open(np,
NULL, 0, 0, /* name nmlen xattr */
rights, &scred,
- &fid, &rightsrcvd, &fa);
+ &fid, &fa);
if (error)
goto out;
smbfs_attrcache_fa(vp, &fa);
@@ -315,24 +327,10 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* We have a new FID and access rights.
*/
oldfid = np->n_fid;
- oldgenid = np->n_vcgenid;
np->n_fid = fid;
- np->n_vcgenid = ssp->ss_vcgenid;
- np->n_rights = rightsrcvd;
np->n_fidrefs++;
- if (np->n_fidrefs > 1 &&
- oldgenid == ssp->ss_vcgenid) {
- /*
- * We already had it open (presumably because
- * it was open with insufficient rights.)
- * Close old wire-open.
- */
- tmperror = smbfs_smb_close(ssp,
- oldfid, NULL, &scred);
- if (tmperror)
- SMBVDEBUG("error %d closing %s\n",
- tmperror, np->n_rpath);
- }
+ if (oldfid != NULL)
+ smb_fh_rele(oldfid);
/*
* This thread did the open.
@@ -478,13 +476,11 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
static void
smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
{
- smb_share_t *ssp;
cred_t *oldcr;
struct smbfs_fctx *fctx;
int error;
- uint16_t ofid;
+ smb_fh_t *ofid;
- ssp = np->n_mount->smi_share;
error = 0;
/* Make sure we serialize for n_dirseq use. */
@@ -513,13 +509,9 @@ smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
ASSERT(np->n_fidrefs > 0);
if (--np->n_fidrefs)
return;
- if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
- np->n_fid = SMB_FID_UNUSED;
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid == ssp->ss_vcgenid) {
- error = smbfs_smb_close(
- ssp, ofid, NULL, scred);
- }
+ if ((ofid = np->n_fid) != NULL) {
+ np->n_fid = NULL;
+ smb_fh_rele(ofid);
}
break;
@@ -557,20 +549,12 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
struct vattr va;
smbnode_t *np;
smbmntinfo_t *smi;
- smb_share_t *ssp;
offset_t endoff;
ssize_t past_eof;
int error;
- caddr_t base;
- u_offset_t off;
- size_t n;
- int on;
- uint_t flags;
-
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -632,12 +616,8 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
return (EINTR);
smb_credinit(&scred, cr);
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_READ,
- uiop, &scred, smb_timo_read);
+ error = smb_rwuio(np->n_fid, UIO_READ,
+ uiop, &scred, smb_timo_read);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -648,8 +628,15 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
return (error);
}
+#ifdef _KERNEL
/* (else) Do I/O through segmap. */
do {
+ caddr_t base;
+ u_offset_t off;
+ size_t n;
+ int on;
+ uint_t flags;
+
off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
n = MIN(MAXBSIZE - on, uiop->uio_resid);
@@ -698,6 +685,9 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
}
}
} while (!error && uiop->uio_resid > 0);
+#else // _KERNEL
+ error = ENOSYS;
+#endif // _KERNEL
/* undo adjustment of resid */
uiop->uio_resid += past_eof;
@@ -715,22 +705,17 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
struct vattr va;
smbnode_t *np;
smbmntinfo_t *smi;
- smb_share_t *ssp;
offset_t endoff, limit;
ssize_t past_limit;
int error, timo;
- caddr_t base;
- u_offset_t off;
- size_t n;
- int on;
- uint_t flags;
u_offset_t last_off;
size_t last_resid;
+#ifdef _KERNEL
uint_t bsize;
+#endif
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -789,12 +774,14 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
limit = MAXOFFSET_T;
if (uiop->uio_loffset >= limit) {
+#ifdef _KERNEL
proc_t *p = ttoproc(curthread);
mutex_enter(&p->p_lock);
(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
p->p_rctls, p, RCA_UNSAFE_SIGINFO);
mutex_exit(&p->p_lock);
+#endif // _KERNEL
return (EFBIG);
}
if (endoff > limit) {
@@ -813,7 +800,9 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
np->r_mapcnt == 0 && np->r_inmap == 0 &&
!vn_has_cached_data(vp))) {
+#ifdef _KERNEL
smbfs_fwrite:
+#endif // _KERNEL
if (np->r_flags & RSTALE) {
last_resid = uiop->uio_resid;
last_off = uiop->uio_loffset;
@@ -837,12 +826,8 @@ smbfs_fwrite:
return (EINTR);
smb_credinit(&scred, cr);
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
- uiop, &scred, timo);
+ error = smb_rwuio(np->n_fid, UIO_WRITE,
+ uiop, &scred, timo);
if (error == 0) {
mutex_enter(&np->r_statelock);
@@ -852,7 +837,7 @@ smbfs_fwrite:
mutex_exit(&np->r_statelock);
if (ioflag & (FSYNC | FDSYNC)) {
/* Don't error the I/O if this fails. */
- (void) smbfs_smb_flush(np, &scred);
+ (void) smbfsflush(np, &scred);
}
}
@@ -865,10 +850,17 @@ smbfs_fwrite:
return (error);
}
+#ifdef _KERNEL
/* (else) Do I/O through segmap. */
bsize = vp->v_vfsp->vfs_bsize;
do {
+ caddr_t base;
+ u_offset_t off;
+ size_t n;
+ int on;
+ uint_t flags;
+
off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
n = MIN(MAXBSIZE - on, uiop->uio_resid);
@@ -993,6 +985,11 @@ smbfs_fwrite:
goto smbfs_fwrite;
}
} while (!error && uiop->uio_resid > 0);
+#else // _KERNEL
+ last_resid = uiop->uio_resid;
+ last_off = uiop->uio_loffset;
+ error = ENOSYS;
+#endif // _KERNEL
bottom:
/* undo adjustment of resid */
@@ -1006,6 +1003,8 @@ bottom:
return (error);
}
+#ifdef _KERNEL
+
/*
* Like nfs_client.c: writerp()
*
@@ -1245,7 +1244,6 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
struct smb_cred scred;
smbnode_t *np = VTOSMB(bp->b_vp);
smbmntinfo_t *smi = np->n_mount;
- smb_share_t *ssp = smi->smi_share;
offset_t offset;
offset_t endoff;
size_t count;
@@ -1301,12 +1299,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
if (bp->b_flags & B_READ) {
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_READ,
- &auio, &scred, smb_timo_read);
+ error = smb_rwuio(np->n_fid, UIO_READ,
+ &auio, &scred, smb_timo_read);
/* Like NFS, only set b_error here. */
bp->b_error = error;
@@ -1320,12 +1314,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
}
} else {
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
- &auio, &scred, smb_timo_write);
+ error = smb_rwuio(np->n_fid, UIO_WRITE,
+ &auio, &scred, smb_timo_write);
/* Like NFS, only set b_error here. */
bp->b_error = error;
@@ -1334,7 +1324,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
if (!error && auio.uio_resid != 0)
error = EIO;
if (!error && sync) {
- (void) smbfs_smb_flush(np, &scred);
+ (void) smbfsflush(np, &scred);
}
}
@@ -1361,6 +1351,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
return (error);
}
+#endif // _KERNEL
/*
* Here NFS has: nfs3write, nfs3read
@@ -1588,12 +1579,12 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
{
int error = 0;
smbnode_t *np = VTOSMB(vp);
+ smbmntinfo_t *smi = np->n_mount;
uint_t mask = vap->va_mask;
struct timespec *mtime, *atime;
struct smb_cred scred;
- int cerror, modified = 0;
- unsigned short fid;
- int have_fid = 0;
+ int modified = 0;
+ smb_fh_t *fid = NULL;
uint32_t rights = 0;
uint32_t dosattr = 0;
@@ -1645,9 +1636,6 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
* with a partially complete request.
*/
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
/*
@@ -1685,7 +1673,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
error, np->n_rpath);
goto out;
}
- have_fid = 1;
+ ASSERT(fid != NULL);
}
/*
@@ -1704,8 +1692,9 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/*
* Set the file size to vap->va_size.
*/
- ASSERT(have_fid);
- error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
+ ASSERT(fid != NULL);
+ error = smbfs_smb_setfsize(smi->smi_share, fid,
+ vap->va_size, &scred);
if (error) {
SMBVDEBUG("setsize error %d file %s\n",
error, np->n_rpath);
@@ -1717,6 +1706,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
*/
mutex_enter(&np->r_statelock);
np->r_size = vap->va_size;
+ np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
mutex_exit(&np->r_statelock);
modified = 1;
}
@@ -1733,8 +1723,8 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/*
* Always use the handle-based set attr call now.
*/
- ASSERT(have_fid);
- error = smbfs_smb_setfattr(np, fid,
+ ASSERT(fid != NULL);
+ error = smbfs_smb_setfattr(smi->smi_share, fid,
dosattr, mtime, atime, &scred);
if (error) {
SMBVDEBUG("set times error %d file %s\n",
@@ -1745,15 +1735,10 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
}
out:
- if (have_fid) {
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing %s\n",
- cerror, np->n_rpath);
- }
+ if (fid != NULL)
+ smbfs_smb_tmpclose(np, fid);
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
if (modified) {
/*
@@ -2022,7 +2007,7 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
return (EINTR);
smb_credinit(&scred, cr);
- error = smbfs_smb_flush(np, &scred);
+ error = smbfsflush(np, &scred);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -2030,6 +2015,37 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
return (error);
}
+static int
+smbfsflush(smbnode_t *np, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp;
+ int error;
+
+ /* Shared lock for n_fid use below. */
+ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+ if (!(np->n_flag & NFLUSHWIRE))
+ return (0);
+ if (np->n_fidrefs == 0)
+ return (0); /* not open */
+ if ((fhp = np->n_fid) == NULL)
+ return (0);
+
+ /* After reconnect, n_fid is invalid */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ error = smbfs_smb_flush(ssp, fhp, scrp);
+
+ if (!error) {
+ mutex_enter(&np->r_statelock);
+ np->n_flag &= ~NFLUSHWIRE;
+ mutex_exit(&np->r_statelock);
+ }
+ return (error);
+}
+
/*
* Last reference to vnode went away.
*/
@@ -2119,8 +2135,8 @@ smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
case VREG:
if (np->n_fidrefs == 0)
break;
- SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
- np->n_fidrefs, np->n_fid, np->n_rpath);
+ SMBVDEBUG("open file: refs %d path %s\n",
+ np->n_fidrefs, np->n_rpath);
/* Force last close. */
np->n_fidrefs = 1;
smbfs_rele_fid(np, &scred);
@@ -2198,6 +2214,14 @@ smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
smbfs_rw_exit(&dnp->r_rwlock);
+ /*
+ * If the caller passes an invalid name here, we'll have
+ * error == EINVAL but want to return ENOENT. This is
+ * common with things like "ls foo*" with no matches.
+ */
+ if (error == EINVAL)
+ error = ENOENT;
+
return (error);
}
@@ -2225,14 +2249,7 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
-#ifdef NOT_YET
- vcp = SSTOVC(smi->smi_share);
-
- /* XXX: Should compute this once and store it in smbmntinfo_t */
- supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
-#else
supplen = 255;
-#endif
/*
* RWlock must be held, either reader or writer.
@@ -2519,7 +2536,6 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
vsecattr_t *vsecp)
{
int error;
- int cerror;
vfs_t *vfsp;
vnode_t *vp;
smbnode_t *np;
@@ -2531,7 +2547,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
const char *name = (const char *)nm;
int nmlen = strlen(nm);
uint32_t disp;
- uint16_t fid;
+ smb_fh_t *fid = NULL;
int xattr;
vfsp = dvp->v_vfsp;
@@ -2693,11 +2709,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* Should use the fid to get/set the size
* while we have it opened here. See above.
*/
-
- cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing %s\\%s\n",
- cerror, dnp->n_rpath, name);
+ smbfs_smb_close(fid);
/*
* In the open case, the name may differ a little
@@ -2766,14 +2778,30 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
/* Lookup the file to remove. */
error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
- if (error == 0) {
- /*
- * Do the real remove work
- */
- error = smbfsremove(dvp, vp, &scred, flags);
- VN_RELE(vp);
+ if (error != 0)
+ goto out;
+
+ /* Don't allow unlink of a directory. */
+ if (vp->v_type == VDIR) {
+ error = EPERM;
+ goto out;
}
+ /*
+ * Do the real remove work
+ */
+ error = smbfsremove(dvp, vp, &scred, flags);
+ if (error != 0)
+ goto out;
+
+#ifdef SMBFS_VNEVENT
+ vnevent_remove(vp, dvp, nm, ct);
+#endif
+
+out:
+ if (vp != NULL)
+ VN_RELE(vp);
+
smb_credrele(&scred);
smbfs_rw_exit(&dnp->r_rwlock);
@@ -2808,11 +2836,11 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
{
smbnode_t *dnp = VTOSMB(dvp);
smbnode_t *np = VTOSMB(vp);
+ smbmntinfo_t *smi = np->n_mount;
char *tmpname = NULL;
int tnlen;
int error;
- unsigned short fid;
- boolean_t have_fid = B_FALSE;
+ smb_fh_t *fid = NULL;
boolean_t renamed = B_FALSE;
/*
@@ -2820,10 +2848,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
*/
ASSERT(dnp->r_rwlock.owner == curthread);
- /* Never allow link/unlink directories on SMB. */
- if (vp->v_type == VDIR)
- return (EPERM);
-
/*
* We need to flush any dirty pages which happen to
* be hanging around before removing the file. This
@@ -2842,10 +2866,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
}
}
- /* Shared lock for n_fid use in smbfs_smb_setdisp etc. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
-
/*
* Get a file handle with delete access.
* Close this FID before return.
@@ -2857,16 +2877,18 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
error, np->n_rpath);
goto out;
}
- have_fid = B_TRUE;
+ ASSERT(fid != NULL);
/*
* If we have the file open, try to rename it to a temporary name.
* If we can't rename, continue on and try setting DoC anyway.
+ * Unnecessary for directories.
*/
- if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
+ if (vp->v_type != VDIR && vp->v_count > 1 && np->n_fidrefs > 0) {
tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
tnlen = smbfs_newname(tmpname, MAXNAMELEN);
- error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0);
+ error = smbfs_smb_rename(dnp, np, dnp, tmpname, tnlen,
+ fid, scred);
if (error != 0) {
SMBVDEBUG("error %d renaming %s -> %s\n",
error, np->n_rpath, tmpname);
@@ -2880,7 +2902,7 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
* Mark the file as delete-on-close. If we can't,
* undo what we did and err out.
*/
- error = smbfs_smb_setdisp(np, fid, 1, scred);
+ error = smbfs_smb_setdisp(smi->smi_share, fid, 1, scred);
if (error != 0) {
SMBVDEBUG("error %d setting DoC on %s\n",
error, np->n_rpath);
@@ -2897,8 +2919,8 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
oldname = np->n_rpath + (dnp->n_rplen + 1);
oldnlen = np->n_rplen - (dnp->n_rplen + 1);
- err2 = smbfs_smb_t2rename(np, oldname, oldnlen,
- scred, fid, 0);
+ err2 = smbfs_smb_rename(dnp, np, dnp, oldname, oldnlen,
+ fid, scred);
SMBVDEBUG("error %d un-renaming %s -> %s\n",
err2, tmpname, np->n_rpath);
}
@@ -2906,19 +2928,14 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
goto out;
}
/* Done! */
+ smbfs_attrcache_remove(np);
smbfs_attrcache_prune(np);
-#ifdef SMBFS_VNEVENT
- vnevent_remove(vp, dvp, nm, ct);
-#endif
-
out:
if (tmpname != NULL)
kmem_free(tmpname, MAXNAMELEN);
-
- if (have_fid)
- (void) smbfs_smb_tmpclose(np, fid, scred);
- smbfs_rw_exit(&np->r_lkserlock);
+ if (fid != NULL)
+ smbfs_smb_tmpclose(np, fid);
if (error == 0) {
/* Keep lookup from finding this node anymore. */
@@ -3050,6 +3067,7 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
vnode_t *nvp = NULL;
int error;
int nvp_locked = 0;
+ smb_fh_t *fid = NULL;
/* Things our caller should have checked. */
ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
@@ -3130,8 +3148,23 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
nvp = NULL;
} /* nvp */
+ /*
+ * Get a file handle with delete access.
+ * Close this FID before return.
+ */
+ error = smbfs_smb_tmpopen(onp, STD_RIGHT_DELETE_ACCESS,
+ scred, &fid);
+ if (error) {
+ SMBVDEBUG("error %d opening %s\n",
+ error, onp->n_rpath);
+ goto out;
+ }
+
smbfs_attrcache_remove(onp);
- error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred);
+ error = smbfs_smb_rename(odnp, onp, ndnp, nnm, strlen(nnm),
+ fid, scred);
+
+ smbfs_smb_tmpclose(onp, fid);
/*
* If the old name should no longer exist,
@@ -3172,7 +3205,7 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
struct smbfattr fattr;
const char *name = (const char *) nm;
int nmlen = strlen(name);
- int error, hiderr;
+ int error;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EPERM);
@@ -3213,10 +3246,6 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
if (error)
goto out;
- if (name[0] == '.')
- if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
- SMBVDEBUG("hide failure %d\n", hiderr);
-
/* Success! */
*vpp = vp;
error = 0;
@@ -3240,12 +3269,12 @@ static int
smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
caller_context_t *ct, int flags)
{
+ struct smb_cred scred;
vnode_t *vp = NULL;
int vp_locked = 0;
struct smbmntinfo *smi = VTOSMI(dvp);
struct smbnode *dnp = VTOSMB(dvp);
struct smbnode *np;
- struct smb_cred scred;
int error;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
@@ -3254,17 +3283,16 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
return (EIO);
- if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
- return (EINTR);
- smb_credinit(&scred, cr);
-
/*
- * Require w/x access in the containing directory.
- * Server handles all other access checks.
+ * Verify access to the dirctory.
*/
- error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
+ error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
if (error)
- goto out;
+ return (error);
+
+ if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+ return (EINTR);
+ smb_credinit(&scred, cr);
/*
* First lookup the entry to be removed.
@@ -3297,23 +3325,17 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
goto out;
}
- smbfs_attrcache_remove(np);
- error = smbfs_smb_rmdir(np, &scred);
-
/*
- * Similar to smbfs_remove
+ * Do the real rmdir work
*/
- switch (error) {
- case 0:
- case ENOENT:
- case ENOTDIR:
- smbfs_attrcache_prune(np);
- break;
- }
-
+ error = smbfsremove(dvp, vp, &scred, flags);
if (error)
goto out;
+#ifdef SMBFS_VNEVENT
+ vnevent_rmdir(vp, dvp, nm, ct);
+#endif
+
mutex_enter(&np->r_statelock);
dnp->n_flag |= NMODIFIED;
mutex_exit(&np->r_statelock);
@@ -3692,6 +3714,8 @@ smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
/* mmap support ******************************************************** */
+#ifdef _KERNEL
+
#ifdef DEBUG
static int smbfs_lostpage = 0; /* number of times we lost original page */
#endif
@@ -4011,6 +4035,8 @@ again:
* No read-ahead in smbfs yet.
*/
+#endif // _KERNEL
+
/*
* Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
* If len == 0, do from off to EOF.
@@ -4026,6 +4052,7 @@ static int
smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
caller_context_t *ct)
{
+#ifdef _KERNEL
smbnode_t *np;
smbmntinfo_t *smi;
page_t *pp;
@@ -4157,8 +4184,14 @@ smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
}
return (error);
+
+#else // _KERNEL
+ return (ENOSYS);
+#endif // _KERNEL
}
+#ifdef _KERNEL
+
/*
* Write out a single page, possibly klustering adjacent dirty pages.
*
@@ -4331,6 +4364,9 @@ smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
return (error);
}
+#endif // _KERNEL
+
+
/*
* NFS has this in nfs_client.c (shared by v2,v3,...)
* We have it here so smbfs_putapage can be file scope.
@@ -4355,8 +4391,10 @@ smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
/* Here NFSv3 has np->r_truncaddr = off; */
mutex_exit(&np->r_statelock);
+#ifdef _KERNEL
(void) pvn_vplist_dirty(vp, off, smbfs_putapage,
B_INVAL | B_TRUNC, cr);
+#endif // _KERNEL
mutex_enter(&np->r_statelock);
np->r_flags &= ~RTRUNCATE;
@@ -4364,6 +4402,8 @@ smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
mutex_exit(&np->r_statelock);
}
+#ifdef _KERNEL
+
/* Like nfs3_map */
/* ARGSUSED */
@@ -4659,6 +4699,8 @@ smbfs_delmap_async(void *varg)
/* No smbfs_pageio() or smbfs_dispose() ops. */
+#endif // _KERNEL
+
/* misc. ******************************************************** */
@@ -4961,11 +5003,13 @@ const fs_operation_def_t smbfs_vnodeops_template[] = {
VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock },
VOPNAME_SPACE, { .vop_space = smbfs_space },
VOPNAME_REALVP, { .vop_realvp = smbfs_realvp },
+#ifdef _KERNEL
VOPNAME_GETPAGE, { .vop_getpage = smbfs_getpage },
VOPNAME_PUTPAGE, { .vop_putpage = smbfs_putpage },
VOPNAME_MAP, { .vop_map = smbfs_map },
VOPNAME_ADDMAP, { .vop_addmap = smbfs_addmap },
VOPNAME_DELMAP, { .vop_delmap = smbfs_delmap },
+#endif // _KERNEL
VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf },
VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr },
VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr },
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
index 75241cc1f0..323b8c8d10 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -29,6 +30,7 @@
*/
#include <sys/systm.h>
+#include <sys/inttypes.h>
#include <sys/cred.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
@@ -43,7 +45,9 @@
#include <sys/u8_textprep.h>
#include <netsmb/smb_osdep.h>
+
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -289,32 +293,20 @@ smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap,
}
/*
- * Fetch the entire attribute list here in findopen.
- * Will parse the results in findnext.
+ * Actually go OtW to get the list of "streams".
*
* This is called on the XATTR directory, so we
* have to get the (real) parent object first.
*/
-/* ARGSUSED */
-int
-smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen)
+static int
+smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx)
{
vnode_t *pvp; /* parent */
smbnode_t *pnp;
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
+ smbnode_t *dnp = ctx->f_dnp;
+ struct mdchain *mdp;
int error;
- ASSERT(dnp->n_flag & N_XATTR);
-
- ctx->f_type = ft_XA;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
-
error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
if (error)
return (error);
@@ -322,40 +314,31 @@ smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
/* Note: pvp has a VN_HOLD */
pnp = VTOSMB(pvp);
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
+ /*
+ * Get stream info into f_mdchain
+ */
+ mdp = &ctx->f_mdchain;
+ md_done(mdp);
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp),
- SMB_TRANS2_QUERY_PATH_INFORMATION,
- ctx->f_scred, &t2p);
+ if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred);
+ } else {
+ error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred);
+ }
if (error)
goto out;
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- (void) mb_init(mbp);
- (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
- (void) mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0);
- if (error)
- goto out;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = INT16_MAX;
- error = smb_t2_request(t2p);
- if (error) {
- if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
- error = ENOTSUP;
- }
/*
- * No returned parameters to parse.
- * Returned data are in t2_rdata,
- * which we'll parse in _findnext.
- * However, save the wildcard.
+ * Have stream info in ctx->f_mdchain
+ * Initialize buffer length, position.
*/
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
+ ctx->f_left = m_fixhdr(mdp->md_top);
+ ctx->f_eofs = 0;
+
+ /*
+ * After one successful call, we're at EOF.
+ */
+ ctx->f_flags |= SMBFS_RDD_EOF;
out:
VN_RELE(pvp);
@@ -363,83 +346,62 @@ out:
}
/*
- * Get the next name in an XATTR directory into f_name
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
*/
-/* ARGSUSED */
int
-smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen)
{
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- uint32_t size, next;
- uint64_t llongint;
- int error, skip, used, nmlen;
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
+ ASSERT(dnp->n_flag & N_XATTR);
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- ASSERT(ctx->f_wildcard);
- SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard);
- }
+ ctx->f_type = ft_XA;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = FileStreamInformation;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
-again:
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
-
- /* Parse FILE_STREAM_INFORMATION */
- if ((error = md_get_uint32le(mdp, &next)) != 0) /* offset to */
- return (ENOENT);
- if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */
- return (ENOENT);
- (void) md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- (void) md_get_uint64le(mdp, NULL); /* alloc. size */
- used = 4 + 4 + 8 + 8; /* how much we consumed */
+ return (0);
+}
- /*
- * Copy the string, but skip the first char (":")
- * Watch out for zero-length strings here.
- */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (size >= 2) {
- size -= 2; used += 2;
- (void) md_get_uint16le(mdp, NULL);
- }
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- } else {
- if (size >= 1) {
- size -= 1; used += 1;
- (void) md_get_uint8(mdp, NULL);
- }
- nmlen = min(size, SMB_MAXFNAMELEN);
- }
- ASSERT(nmlen < ctx->f_namesz);
- ctx->f_nmlen = nmlen;
- error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);
- if (error)
- return (error);
- used += nmlen;
+/*
+ * Get the next name in an XATTR directory
+ */
+/* ARGSUSED */
+int
+smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
/*
- * Convert UCS-2 to UTF-8
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
*/
- smbfs_fname_tolocal(ctx);
- if (nmlen)
- SMBVDEBUG("name: %s\n", ctx->f_name);
- else
- SMBVDEBUG("null name!\n");
+again:
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_xa_get_streaminfo(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
/*
- * Skip padding until next offset
+ * Decode one entry, advance f_eofs
*/
- if (next > used) {
- skip = next - used;
- (void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
- }
- if (next == 0)
- ctx->f_flags |= SMBFS_RDD_EOF;
+ error = smbfs_decode_dirent(ctx);
+ if (error)
+ return (error);
+ SMBVDEBUG("name: %s\n", ctx->f_name);
/*
* Chop off the trailing ":$DATA"
@@ -462,8 +424,10 @@ again:
goto again;
/*
- * If this is a lookup of a specific name,
- * skip past any non-matching names.
+ * When called by lookup, we'll have the "single" flag,
+ * and a name with no wildcards. We need to filter here
+ * because smbfs_xa_get_streaminfo() gets ALL the names
+ * (not just those matching our pattern).
*/
if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
if (ctx->f_wclen != ctx->f_nmlen)
@@ -488,8 +452,6 @@ smbfs_xa_findclose(struct smbfs_fctx *ctx)
if (ctx->f_name)
kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
return (0);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
index f4a9f9a948..4ed5cba79c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
@@ -22,7 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -31,7 +31,7 @@
*/
#include <smbsrv/smb2_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
struct smb2_ioctbl_ent {
uint32_t te_code;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
index ffe230f888..6176a8b002 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -30,7 +30,7 @@
#include <smbsrv/string.h>
#include <smbsrv/nmpipes.h>
#include <smbsrv/mailslot.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* count of bytes in server response packet
@@ -943,7 +943,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
data_off, /* Data offset from header start */
data_disp, /* Data displacement */
n_setup, /* suwcnt */
- &xa->rep_setup_mb, /* setup[] */
+ &xa->rep_setup_mb, /* setup[] */
tot_packet_bytes, /* Total data bytes */
param_pad,
&xa->rep_param_mb,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
index 495965859b..03c565e9e4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
@@ -22,13 +22,13 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_dfs.h>
#include <smbsrv/smb_door.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* Get Referral response header flags
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
index c0ab285bd5..f355e314bc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -20,11 +20,11 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index 273a2f7297..c08cba0ac6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -35,7 +35,7 @@
#include <sys/filio.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_xdr.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
static uint32_t smb_opipe_transceive(smb_request_t *, smb_fsctl_t *);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
index df874ffe1d..918bf78727 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
@@ -22,11 +22,11 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* [MS-CIFS]
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vss.c b/usr/src/uts/common/fs/smbsrv/smb_vss.c
index 211bc467a8..72657ae3be 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vss.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c
@@ -41,7 +41,7 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/string.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
#include <smbsrv/smb_door.h>
/* Size of the token on the wire due to encoding */
diff --git a/usr/src/uts/common/io/aac/aac.c b/usr/src/uts/common/io/aac/aac.c
index 36c48d96e6..f9d3672963 100644
--- a/usr/src/uts/common/io/aac/aac.c
+++ b/usr/src/uts/common/io/aac/aac.c
@@ -255,8 +255,8 @@ static int aac_add_intrs(struct aac_softstate *);
static void aac_remove_intrs(struct aac_softstate *);
static int aac_enable_intrs(struct aac_softstate *);
static int aac_disable_intrs(struct aac_softstate *);
-static uint_t aac_intr_old(caddr_t);
-static uint_t aac_intr_new(caddr_t);
+static uint_t aac_intr_old(caddr_t, caddr_t);
+static uint_t aac_intr_new(caddr_t, caddr_t);
static uint_t aac_softintr(caddr_t);
/*
@@ -1416,7 +1416,7 @@ aac_process_intr_new(struct aac_softstate *softs)
}
static uint_t
-aac_intr_new(caddr_t arg)
+aac_intr_new(caddr_t arg, caddr_t arg1 __unused)
{
struct aac_softstate *softs = (void *)arg;
uint_t rval;
@@ -1555,7 +1555,7 @@ aac_process_intr_old(struct aac_softstate *softs)
}
static uint_t
-aac_intr_old(caddr_t arg)
+aac_intr_old(caddr_t arg, caddr_t arg1 __unused)
{
struct aac_softstate *softs = (void *)arg;
int rval;
@@ -1674,7 +1674,7 @@ aac_add_intrs(struct aac_softstate *softs)
ddi_intr_handler_t *aac_intr;
actual = softs->intr_cnt;
- aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
+ aac_intr = ((softs->flags & AAC_FLAGS_NEW_COMM) ?
aac_intr_new : aac_intr_old);
/* Call ddi_intr_add_handler() */
diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h
index c5c8512fd7..156671999b 100644
--- a/usr/src/uts/common/netsmb/mchain.h
+++ b/usr/src/uts/common/netsmb/mchain.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _MCHAIN_H_
@@ -70,10 +72,10 @@
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
/* little-endian values on big-endian (swap) */
-#define letohs(x) BSWAP_16(x)
-#define htoles(x) BSWAP_16(x)
-#define letohl(x) BSWAP_32(x)
-#define htolel(x) BSWAP_32(x)
+#define letohs(x) BSWAP_16(x)
+#define htoles(x) BSWAP_16(x)
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
#define letohq(x) BSWAP_64(x)
#define htoleq(x) BSWAP_64(x)
@@ -93,7 +95,7 @@
* wrappers for streams functions. See: subr_mchain.c
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* BSD-style mbuf "shim" for kernel code. Note, this
@@ -103,6 +105,7 @@
*/
#include <sys/stream.h> /* mblk_t */
+#include <sys/strsun.h> /* MBLKL */
typedef mblk_t mbuf_t;
/* BEGIN CSTYLED */
@@ -112,9 +115,9 @@ typedef mblk_t mbuf_t;
* m_data ... (m_data + m_len)
* In Unix STREAMS, the mblk payload is:
* b_rptr ... b_wptr
- *
+ *
* Here are some handy conversion notes:
- *
+ *
* struct mbuf struct mblk
* m->m_next m->b_cont
* m->m_nextpkt m->b_next
@@ -124,7 +127,7 @@ typedef mblk_t mbuf_t;
* &m->m_dat[MLEN] m->b_datap->db_lim
* M_TRAILINGSPACE(m) MBLKTAIL(m)
* m_freem(m) freemsg(m)
- *
+ *
* Note that mbufs chains also have a special "packet" header,
* which has the length of the whole message. In STREAMS one
* typically just calls msgdsize(m) to get that.
@@ -177,7 +180,7 @@ void m_freem(mbuf_t *);
#define MB_MZERO 3 /* bzero(), mb_put_mem only */
#define MB_MCUSTOM 4 /* use an user defined function */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
struct mbchain {
mblk_t *mb_top;
@@ -224,6 +227,7 @@ void mb_initm(mbchain_t *, mbuf_t *);
void mb_done(mbchain_t *);
void *mb_reserve(mbchain_t *, int size);
+int mb_put_align8(mbchain_t *mbp);
int mb_put_padbyte(mbchain_t *mbp);
int mb_put_uint8(mbchain_t *, uint8_t);
int mb_put_uint16be(mbchain_t *, uint16_t);
@@ -234,6 +238,7 @@ int mb_put_uint64be(mbchain_t *, uint64_t);
int mb_put_uint64le(mbchain_t *, uint64_t);
int mb_put_mem(mbchain_t *, const void *, int, int);
int mb_put_mbuf(mbchain_t *, mbuf_t *);
+int mb_put_mbchain(mbchain_t *, mbchain_t *);
int md_init(mdchain_t *mdp);
void md_initm(mdchain_t *mbp, mbuf_t *m);
@@ -248,5 +253,7 @@ int md_get_uint64be(mdchain_t *, uint64_t *);
int md_get_uint64le(mdchain_t *, uint64_t *);
int md_get_mem(mdchain_t *, void *, int, int);
int md_get_mbuf(mdchain_t *, int, mbuf_t **);
+int md_seek(mdchain_t *, uint32_t);
+uint32_t md_tell(mdchain_t *);
#endif /* !_MCHAIN_H_ */
diff --git a/usr/src/uts/common/netsmb/smb.h b/usr/src/uts/common/netsmb/smb.h
index e3bfc5144c..b57be5bbfe 100644
--- a/usr/src/uts/common/netsmb/smb.h
+++ b/usr/src/uts/common/netsmb/smb.h
@@ -40,6 +40,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_H_
@@ -66,8 +67,8 @@ enum smb_dialects {
SMB_DIALECT_LANMAN1_0, /* MICROSOFT NETWORKS 3.0, LANMAN1.0 */
SMB_DIALECT_LANMAN2_0, /* LM1.2X002, DOS LM1.2X002, Samba */
SMB_DIALECT_LANMAN2_1, /* DOS LANMAN2.1, LANMAN2.1 */
- SMB_DIALECT_NTLM0_12 /* NT LM 0.12, Windows for Workgroups */
- /* 3.1a, * NT LANMAN 1.0 */
+ SMB_DIALECT_NTLM0_12, /* NT LM 0.12, etc. */
+ SMB_DIALECT_SMB2_FF /* SMB1 negotiate to SMB2 */
};
/*
@@ -82,11 +83,18 @@ enum smb_dialects {
/*
* SMB header
*/
+
#define SMB_SIGNATURE "\xFFSMB"
#define SMB_SIGLEN 4
#define SMB_HDRCMD(p) (*((uchar_t *)(p) + SMB_SIGLEN))
#define SMB_HDRMID(p) (*(ushort_t *)((uchar_t *)(p) + 30))
+#define SMB_HDR_OFF_MID 30
#define SMB_HDRLEN 32
+
+#define SMB_HDR_V1 0xFF
+#define SMB_HDR_V2 0xFE
+#define SMB_HDR_V3E 0xFD /* SMB3 encrypted */
+
/*
* bits in the smb_flags field
*/
@@ -151,6 +159,25 @@ enum smb_dialects {
#define SMB_CAP_COMPRESSED_DATA 0x40000000
#define SMB_CAP_EXT_SECURITY 0x80000000
+/* SMB_COM_TREE_CONNECT_ANDX flags. See [MS-SMB] for a complete description. */
+#define TREE_CONNECT_ANDX_DISCONNECT_TID 0x0001
+#define TREE_CONNECT_ANDX_EXTENDED_SIGNATURES 0x0004
+#define TREE_CONNECT_ANDX_EXTENDED_RESPONSE 0x0008
+
+/*
+ * SMB_COM_TREE_CONNECT_ANDX optional support flags. See [MS-SMB] for a
+ * complete description.
+ */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* supports SearchAttributes */
+#define SMB_SHARE_IS_IN_DFS 0x0002 /* share is managed by DFS */
+#define SMB_CSC_MASK 0x000C /* Offline-caching bits. */
+#define SMB_UNIQUE_FILE_NAME 0x0010 /* Long file names only */
+#define SMB_EXTENDED_SIGNATURES 0x0020 /* Signing key protection. */
+/* See [MS-SMB] for a complete description of SMB_CSC_MASK bits. */
+#define SMB_CSC_CACHE_MANUAL_REINT 0x0000
+#define SMB_CSC_CACHE_AUTO_REINT 0x0004
+#define SMB_CSC_CACHE_VDO 0x0008
+
/*
* File attributes
*/
@@ -372,6 +399,7 @@ enum smb_dialects {
#define SMB_QFS_DEVICE_INFO 0x104
#define SMB_QFS_ATTRIBUTE_INFO 0x105
#define SMB_QFS_UNIX_INFO 0x200
+#define SMB_QFS_POSIX_WHOAMI 0x202
#define SMB_QFS_MAC_FS_INFO 0x301
#define SMB_QFS_VOLUME_INFORMATION 1001
#define SMB_QFS_SIZE_INFORMATION 1003
@@ -381,6 +409,11 @@ enum smb_dialects {
#define SMB_QFS_FULL_SIZE_INFORMATION 1007
#define SMB_QFS_OBJECTID_INFORMATION 1008
+/*
+ * NT Notify Change Compeletion Filter
+ * NT Notify Actions
+ * (We don't use these.)
+ */
/*
* SMB_QFS_ATTRIBUTE_INFO bits.
@@ -403,6 +436,7 @@ enum smb_dialects {
#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
#define FILE_SUPPORTS_ENCRYPTION 0x00020000
#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
/*
* SMB_TRANS2_QUERY_PATH levels
@@ -424,9 +458,12 @@ enum smb_dialects {
#define SMB_QFILEINFO_COMPRESSION_INFO 0x10b
#define SMB_QFILEINFO_UNIX_BASIC 0x200
#define SMB_QFILEINFO_UNIX_LINK 0x201
+#define SMB_QFILEINFO_POSIX_ACL 0x204
+#define SMB_QFILEINFO_UNIX_INFO2 0x20B
#define SMB_QFILEINFO_MAC_DT_GET_APPL 0x306
#define SMB_QFILEINFO_MAC_DT_GET_ICON 0x307
#define SMB_QFILEINFO_MAC_DT_GET_ICON_INFO 0x308
+#define SMB_QFILEINFO_MAC_SPOTLIGHT 0x310
#define SMB_QFILEINFO_BASIC_INFORMATION 1004
#define SMB_QFILEINFO_STANDARD_INFORMATION 1005
#define SMB_QFILEINFO_INTERNAL_INFORMATION 1006
@@ -454,6 +491,9 @@ enum smb_dialects {
#define SMB_FIND_NAME_INFO 0x103
#define SMB_FIND_BOTH_DIRECTORY_INFO 0x104
#define SMB_FIND_UNIX_INFO 0x200
+/* Transact 2 Find First levels */
+#define SMB_FIND_FILE_UNIX 0x202
+#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
/*
* Selectors for NT_TRANSACT_QUERY_SECURITY_DESC and
@@ -707,6 +747,9 @@ typedef struct ntsid ntsid_t;
#define SMB_SFILEINFO_UNIX_BASIC 0x200
#define SMB_SFILEINFO_UNIX_LINK 0x201
#define SMB_SFILEINFO_UNIX_HLINK 0x203
+#define SMB_SFILEINFO_POSIX_ACL 0x204
+#define SMB_SFILEINFO_POSIX_UNLINK 0x20A
+#define SMB_SFILEINFO_UNIX_INFO2 0x20B
#define SMB_SFILEINFO_DIRECTORY_INFORMATION 1001
#define SMB_SFILEINFO_FULL_DIRECTORY_INFORMATION 1002
#define SMB_SFILEINFO_BOTH_DIRECTORY_INFORMATION 1003
@@ -816,4 +859,19 @@ typedef struct ntlmv2_namehdr ntlmv2_namehdr_t;
#define STYPE_TEMPORARY 0x40000000
#define STYPE_HIDDEN 0x80000000
+/*
+ * Characters that are not allowed in an SMB file name component.
+ * From MSDN: Naming Files, Paths, ...
+ * < (less than)
+ * > (greater than)
+ * : (colon)
+ * " (double quote)
+ * / (forward slash)
+ * \ (backslash)
+ * | (vertical bar or pipe)
+ * ? (question mark)
+ * * (asterisk)
+ */
+#define SMB_FILENAME_INVALID_CHARS "<>:\"/\\|?*"
+
#endif /* _NETSMB_SMB_H_ */
diff --git a/usr/src/uts/common/netsmb/smb2.h b/usr/src/uts/common/netsmb/smb2.h
new file mode 100644
index 0000000000..abae5e8063
--- /dev/null
+++ b/usr/src/uts/common/netsmb/smb2.h
@@ -0,0 +1,465 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _NETSMB_SMB2_H
+#define _NETSMB_SMB2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB2_PROTOCOL_ID { 0xFE, 'S', 'M', 'B' }
+#define SMB2_HDR_SIZE 64
+#define SMB2_HDRLEN SMB2_HDR_SIZE
+
+/*
+ * SMB2 header command codes.
+ * These are uint16_t on the wire.
+ */
+typedef enum {
+ SMB2_NEGOTIATE = 0,
+ SMB2_SESSION_SETUP,
+ SMB2_LOGOFF,
+ SMB2_TREE_CONNECT,
+ SMB2_TREE_DISCONNECT,
+ SMB2_CREATE,
+ SMB2_CLOSE,
+ SMB2_FLUSH,
+ SMB2_READ,
+ SMB2_WRITE,
+ SMB2_LOCK,
+ SMB2_IOCTL,
+ SMB2_CANCEL,
+ SMB2_ECHO,
+ SMB2_QUERY_DIRECTORY,
+ SMB2_CHANGE_NOTIFY,
+ SMB2_QUERY_INFO,
+ SMB2_SET_INFO,
+ SMB2_OPLOCK_BREAK,
+ /*
+ * The above (oplock break) is the last real SMB2 op-code.
+ * We use one more slot to represent invalid commands, and
+ * the final enum value is used for array sizes. Keep last!
+ */
+ SMB2_INVALID_CMD,
+ SMB2__NCMDS
+} SMB2_cmd_code;
+
+/*
+ * SMB2 header flags.
+ */
+
+/*
+ * SERVER_TO_REDIR
+ * When set, indicates the message is a response rather than
+ * a request. This MUST be set on responses sent from the
+ * server to the client, and MUST NOT be set on requests
+ * sent from the client to the server.
+ */
+#define SMB2_FLAGS_SERVER_TO_REDIR 0x00000001
+
+/*
+ * ASYNC_COMMAND
+ * When set, indicates that this is an ASYNC SMB2 header.
+ * Always set for headers of the form described in this
+ * section.
+ */
+#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002
+
+/*
+ * RELATED_OPERATIONS
+ * When set in an SMB2 request, indicates that this request
+ * is a related operation in a compounded request chain.
+ * [MS-SMB2 sec. 3.2.4.1.4]
+ *
+ * When set in an SMB2 compound response, indicates that
+ * the request corresponding to this response was part of a
+ * related operation in a compounded request chain.
+ * [MS-SMB2 sec. 3.3.5.2.7.2]
+ */
+#define SMB2_FLAGS_RELATED_OPERATIONS 0x00000004
+
+/*
+ * SIGNED
+ * When set, indicates that this packet has been signed.
+ * [MS-SMB2 3.1.5.1]
+ */
+#define SMB2_FLAGS_SIGNED 0x00000008
+
+/*
+ * [MS-SMB2] 3.2.5.3.1 The SessionKey MUST be set to the
+ * first 16 bytes of the cryptographic key from GSSAPI.
+ * (Padded with zeros if the GSSAPI key is shorter.)
+ */
+#define SMB2_SESSION_KEY_LEN 16
+
+/*
+ * DFS_OPERATIONS
+ * When set, indicates that this command is a Distributed
+ * File System (DFS) operation. [MS-SMB2 3.3.5.9]
+ */
+#define SMB2_FLAGS_DFS_OPERATIONS 0x10000000
+
+/*
+ * REPLAY_OPERATION
+ * This flag is only valid for the SMB 3.0 dialect. When set,
+ * it indicates that this command is a replay operation.
+ * The client MUST ignore this bit on receipt.
+ */
+#define SMB2_FLAGS_REPLAY_OPERATION 0x20000000
+
+/*
+ * SMB2 Netgotiate [MS-SMB2 2.2.3]
+ */
+
+#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02
+
+#define SMB2_CAP_DFS 0x00000001
+
+/* Added with SMB2.1 */
+#define SMB2_CAP_DFS 0x00000001
+#define SMB2_CAP_LEASING 0x00000002
+/*
+ * LARGE_MTU:
+ * When set, indicates that the client supports multi-credit operations.
+ */
+#define SMB2_CAP_LARGE_MTU 0x00000004
+
+/* Added with SMB3.0 */
+#define SMB2_CAP_MULTI_CHANNEL 0x00000008
+#define SMB2_CAP_PERSISTENT_HANDLES 0x00000010
+#define SMB2_CAP_DIRECTORY_LEASING 0x00000020
+#define SMB2_CAP_ENCRYPTION 0x00000040
+
+/* SMB2 session flags */
+#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
+#define SMB2_SESSION_FLAG_IS_NULL 0x0002
+#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
+
+/*
+ * SMB2 Tree connect, disconnect
+ */
+
+/* SMB2 sharetype flags */
+#define SMB2_SHARE_TYPE_DISK 0x1
+#define SMB2_SHARE_TYPE_PIPE 0x2
+#define SMB2_SHARE_TYPE_PRINT 0x3
+
+/* SMB2 share flags */
+#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000
+#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010
+#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020
+#define SMB2_SHAREFLAG_NO_CACHING 0x00000030
+#define SMB2_SHAREFLAG_DFS 0x00000001
+#define SMB2_SHAREFLAG_DFS_ROOT 0x00000002
+#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x00000100
+#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x00000200
+#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x00000400
+#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x00000800
+#define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK 0x00001000
+/* SMB 3.0 */
+#define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x00002000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x00004000
+#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x00008000
+
+/* SMB2 share capabilities */
+#define SMB2_SHARE_CAP_DFS 0x00000008
+/* SMB 3.0 */
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x00000010
+#define SMB2_SHARE_CAP_SCALEOUT 0x00000020
+#define SMB2_SHARE_CAP_CLUSTER 0x00000040
+
+/*
+ * SMB2 Create (open)
+ */
+
+/* SMB2 requested oplock levels */
+#define SMB2_OPLOCK_LEVEL_NONE 0x00
+#define SMB2_OPLOCK_LEVEL_II 0x01
+#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
+#define SMB2_OPLOCK_LEVEL_BATCH 0x09
+#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
+
+/* SMB2 impersonation levels */
+#define SMB2_IMPERSONATION_ANONYMOUS 0x00
+#define SMB2_IMPERSONATION_IDENTIFICATION 0x01
+#define SMB2_IMPERSONATION_IMPERSONATION 0x02
+#define SMB2_IMPERSONATION_DELEGATE 0x03
+
+/*
+ * Note: ShareAccess, CreateDispositon, CreateOptions,
+ * all use the same definitions as SMB1 (from MS-FSA).
+ * Ditto FileAccess flags (as with ACLs)
+ */
+
+/* SMB2 Create Context tags */
+
+#define SMB2_CREATE_EA_BUFFER 0x45787441 /* ("ExtA") */
+/*
+ * The data contains the extended attributes
+ * that MUST be stored on the created file.
+ * This value MUST NOT be set for named
+ * pipes and print files.
+ */
+
+#define SMB2_CREATE_SD_BUFFER 0x53656344 /* ("SecD") */
+/*
+ * The data contains a security descriptor that
+ * MUST be stored on the created file.
+ * This value MUST NOT be set for named
+ * pipes and print files.
+ */
+
+#define SMB2_CREATE_DURABLE_HANDLE_REQUEST 0x44486e51 /* ("DHnQ") */
+/* The client is requesting the open to be durable */
+
+#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT 0x44486e43 /* ("DHnC") */
+/*
+ * The client is requesting to reconnect to a
+ * durable open after being disconnected
+ */
+
+#define SMB2_CREATE_ALLOCATION_SIZE 0x416c5369 /* ("AISi") */
+/*
+ * The data contains the required allocation
+ * size of the newly created file.
+ */
+
+#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS 0x4d784163 /* ("MxAc") */
+/*
+ * The client is requesting that the server
+ * return maximal access information.
+ */
+
+#define SMB2_CREATE_TIMEWARP_TOKEN 0x54577270 /* ("TWrp") */
+/*
+ * The client is requesting that the server
+ * open an earlier version of the file identified
+ * by the provided time stamp.
+ */
+
+#define SMB2_CREATE_QUERY_ON_DISK_ID 0x51466964 /* ("QFid") */
+/*
+ * The client is requesting that the server return a 32-byte
+ * opaque BLOB that uniquely identifies the file being opened
+ * on disk. No data is passed to the server by the client.
+ */
+
+#define SMB2_CREATE_REQUEST_LEASE 0x52714c73 /* ("RqLs") */
+/*
+ * The client is requesting that the server return a lease.
+ * This value is only supported for the SMB 2.1 and 3.0 dialects.
+ */
+
+/* SMB2 create request lease */
+#define SMB2_LEASE_NONE 0x00
+#define SMB2_LEASE_READ_CACHING 0x01
+#define SMB2_LEASE_HANDLE_CACHING 0x02
+#define SMB2_LEASE_WRITE_CACHING 0x04
+
+/* SMB2 lease break notification flags */
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED 0x01
+
+/*
+ * SMB2 Close
+ */
+#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB 0x0001
+
+/*
+ * SMB2 Write
+ */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+/*
+ * SMB2 Lock Request
+ */
+
+/* SMB2 lock flags */
+
+/*
+ * SMB2_LOCKFLAG_SHARED_LOCK
+ * The range MUST be locked shared, allowing other opens
+ * to read from or take a shared lock on the range. All opens
+ * MUST NOT be allowed to write within the range. Other
+ * locks can be requested and taken on this range.
+ */
+#define SMB2_LOCKFLAG_SHARED_LOCK 0x00000001
+
+/*
+ * SMB2_LOCKFLAG_EXCLUSIVE_LOCK
+ * The range MUST be locked exclusive, not allowing other
+ * opens to read, write, or lock within the range.
+ */
+#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x00000002
+
+/*
+ * SMB2_LOCKFLAG_UNLOCK
+ * The range MUST be unlocked from a previous lock taken
+ * on this range. The unlock range MUST be identical to the
+ * lock range. Sub-ranges cannot be unlocked.
+ */
+#define SMB2_LOCKFLAG_UNLOCK 0x00000004
+
+/*
+ * SMB2_LOCKFLAG_FAIL_IMMEDIATELY
+ * The lock operation MUST fail immediately if it conflicts
+ * with an existing lock, instead of waiting for the range to
+ * become available. This can be OR'ed with either of
+ * shared_lock, exclusive_lock (nothing else).
+ */
+#define SMB2_LOCKFLAG_FAIL_IMMEDIATELY 0x00000010
+
+/*
+ * SMB2 Ioctl Request
+ */
+#define SMB2_IOCTL_IS_FSCTL 0x00000001
+
+
+/*
+ * SMB2 Query Directory
+ */
+
+/*
+ * SMB2 query directory info levels
+ * Same as SMB1 (see ntifs.h)
+ */
+
+/*
+ * SMB2 Query Directory Flags
+ * (our own names for these - spec. used poor names)
+ */
+#define SMB2_QDIR_FLAG_RESTART 0x01 /* SMB2_RESTART_SCANS */
+#define SMB2_QDIR_FLAG_SINGLE 0x02 /* SMB2_RETURN_SINGLE_ENTRY */
+#define SMB2_QDIR_FLAG_INDEX 0x04 /* SMB2_INDEX_SPECIFIED */
+#define SMB2_QDIR_FLAG_REOPEN 0x10 /* SMB2_REOPEN */
+
+/*
+ * SMB2 Query Info Request
+ */
+
+/* info type */
+#define SMB2_0_INFO_FILE 0x01
+/* The file information is requested. */
+#define SMB2_0_INFO_FILESYSTEM 0x02
+/* The underlying object store information is requested. */
+#define SMB2_0_INFO_SECURITY 0x03
+/* The security information is requested. */
+#define SMB2_0_INFO_QUOTA 0x04
+/* The underlying object store quota information is requested. */
+
+/*
+ * MS-FSCC 2.5 FileSystem Information Classes.
+ * Also see MSDN for ZwQueryVolumeInformationFile.
+ */
+typedef enum _FS_INFORMATION_CLASS
+{
+ FileFsVolumeInformation = 1, /* Query */
+ FileFsLabelInformation = 2, /* Set */
+ FileFsSizeInformation = 3, /* Query */
+ FileFsDeviceInformation = 4, /* Query */
+ FileFsAttributeInformation = 5, /* Query */
+ FileFsControlInformation = 6, /* Query, Set */
+ FileFsFullSizeInformation = 7, /* Query */
+ FileFsObjectIdInformation = 8, /* Query, Set */
+ FileFsDriverPathInformation = 9 /* Query */
+} FS_INFORMATION_CLASS;
+
+/*
+ * MS-FSCC 2.4 File Information Classes
+ */
+typedef enum _FILE_INFORMATION_CLASS
+{
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation = 2,
+ FileBothDirectoryInformation = 3,
+ FileBasicInformation = 4,
+ FileStandardInformation = 5,
+ FileInternalInformation = 6,
+ FileEaInformation = 7,
+ FileAccessInformation = 8,
+ FileNameInformation = 9,
+ FileRenameInformation = 10,
+ FileLinkInformation = 11,
+ FileNamesInformation = 12,
+ FileDispositionInformation = 13,
+ FilePositionInformation = 14,
+ FileFullEaInformation = 15,
+ FileModeInformation = 16,
+ FileAlignmentInformation = 17,
+ FileAllInformation = 18,
+ FileAllocationInformation = 19,
+ FileEndOfFileInformation = 20,
+ FileAlternateNameInformation = 21,
+ FileStreamInformation = 22,
+ FilePipeInformation = 23,
+ FilePipeLocalInformation = 24,
+ FilePipeRemoteInformation = 25,
+ FileMailslotQueryInformation = 26,
+ FileMailslotSetInformation = 27,
+ FileCompressionInformation = 28,
+ FileObjectIdInformation = 29,
+ FileMoveClusterInformation = 31,
+ FileQuotaInformation = 32,
+ FileReparsePointInformation = 33,
+ FileNetworkOpenInformation = 34,
+ FileAttributeTagInformation = 35,
+ FileTrackingInformation = 36,
+ FileIdBothDirectoryInformation = 37,
+ FileIdFullDirectoryInformation = 38,
+ FileValidDataLengthInformation = 39,
+ FileShortNameInformation = 40,
+ FileSfioReserveInformation = 44,
+ FileSfioVolumeInformation = 45,
+ FileHardLinkInformation = 46,
+ FileNormalizedNameInformation = 48,
+ FileIdGlobalTxDirectoryInformation = 50,
+ FileStandardLinkInformation = 54
+} FILE_INFORMATION_CLASS;
+
+/*
+ * SMB2 Change Nofity Request
+ */
+#define SMB2_WATCH_TREE 0x00000001
+
+/*
+ * After here, added stuff from darwin
+ */
+#define SMB2_TID_UNKNOWN 0
+#define SMB2_FID_UNUSED 0xffffffffffffffff
+
+/* smb2_durable_handle flags */
+typedef enum _SMB2_DURABLE_HANDLE_FLAGS
+{
+ SMB2_DURABLE_HANDLE_REQUEST = 0x0001,
+ SMB2_DURABLE_HANDLE_RECONNECT = 0x0002,
+ SMB2_DURABLE_HANDLE_GRANTED = 0x0004,
+ SMB2_LEASE_GRANTED = 0x0008
+} _SMB2_DURABLE_HANDLE_FLAGS;
+
+struct smb2_durable_handle {
+ uint64_t fid; /* SMBFID to reconnect in durable handle reconnect */
+ uint64_t flags;
+ uint64_t lease_key_hi; /* atomic increment number */
+ uint64_t lease_key_low; /* node hash value */
+ uint32_t lease_state;
+ uint32_t pad;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMB2_H */
diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h
index d2e7690062..817d214b3e 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_DEV_H_
@@ -71,9 +72,9 @@
* associated structures change in ways that would
* make them incompatible with an old driver.
*/
-#define NSMB_VERMAJ 1
-#define NSMB_VERMIN 4000
-#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN)
+#define NSMB_VERMAJ 2
+#define NSMB_VERMIN 0x100
+#define NSMB_VERSION ((NSMB_VERMAJ << 16) | NSMB_VERMIN)
/*
* Some errno values we need to expose to the library.
@@ -84,7 +85,7 @@
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -111,13 +112,21 @@
#define SMBVOPT_PRIVATE 0x0002 /* connection should be private */
#define SMBVOPT_SINGLESHARE 0x0004 /* keep only one share at this VC */
#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */
-#define SMBVOPT_EXT_SEC 0x0020 /* extended security negotiation */
-#define SMBVOPT_USE_KEYCHAIN 0x0040 /* get p/w from keychain */
-#define SMBVOPT_KC_DOMAIN 0x0080 /* keychain lookup uses domain */
+#define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */
+
+#define SMBVOPT_SIGNING_ENABLED 0x10000 /* sign if server agrees */
+#define SMBVOPT_SIGNING_REQUIRED 0x20000 /* signing required */
+#define SMBVOPT_SIGNING_MASK 0x30000 /* all signing bits */
-#define SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */
-#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */
-#define SMBVOPT_SIGNING_MASK 0x0300 /* all signing bits */
+#define SMB2_DIALECT_BASE 0x0200
+#define SMB2_DIALECT_0202 0x0202
+#define SMB2_DIALECT_02ff 0x02ff
+#define SMB2_DIALECT_0210 0x0210
+#define SMB2_DIALECT_0300 0x0300
+#define SMB2_DIALECT_0302 0x0302
+
+/* Maximum supported dialect (for ssn_maxver) */
+#define SMB2_DIALECT_MAX SMB2_DIALECT_0210
/*
* Option flags in smbioc_oshare.ioc_opt
@@ -137,13 +146,18 @@
/*
* network IO daemon states
- * really connection states.
*/
enum smbiod_state {
- SMBIOD_ST_IDLE = 0, /* no user requests enqueued yet */
- SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
+ SMBIOD_ST_UNINIT = 0, /* uninitialized */
+ SMBIOD_ST_RECONNECT, /* a [re]connect attempt requested */
SMBIOD_ST_RCFAILED, /* a reconnect attempt has failed */
- SMBIOD_ST_VCACTIVE, /* session established */
+ SMBIOD_ST_CONNECTED, /* Transport (TCP) connected */
+ SMBIOD_ST_NEGOTIATED, /* Negotiated SMB/SMB2+ */
+ SMBIOD_ST_AUTHCONT, /* Session setup continuing */
+ SMBIOD_ST_AUTHFAIL, /* Session setup failed */
+ SMBIOD_ST_AUTHOK, /* Session setup success */
+ SMBIOD_ST_VCACTIVE, /* iod_work running */
+ SMBIOD_ST_IDLE, /* no trees, will go DEAD */
SMBIOD_ST_DEAD /* connection gone, no IOD */
};
@@ -204,8 +218,10 @@ typedef struct smbioc_ssn_ident smbioc_ssn_ident_t;
* Structure used with SMBIOC_SSN_FIND, _CREATE
*/
struct smbioc_ossn {
- uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
uint32_t ssn_owner; /* Unix owner (UID) */
+ uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
+ uint16_t ssn_minver; /* Min SMB version. */
+ uint16_t ssn_maxver; /* Max SMB version. */
smbioc_ssn_ident_t ssn_id;
char ssn_srvname[SMBIOC_MAX_NAME];
};
@@ -232,55 +248,19 @@ typedef struct smbioc_tcon {
smbioc_oshare_t tc_sh;
} smbioc_tcon_t;
-
-/*
- * Negotiated protocol parameters
- */
-struct smb_sopt {
- int16_t sv_proto; /* protocol dialect */
- uchar_t sv_sm; /* security mode */
- int16_t sv_tz; /* offset in min relative to UTC */
- uint16_t sv_maxmux; /* max number of outstanding rq's */
- uint16_t sv_maxvcs; /* max number of VCs */
- uint16_t sv_rawmode;
- uint32_t sv_maxtx; /* maximum transmit buf size */
- uint32_t sv_maxraw; /* maximum raw-buffer size */
- uint32_t sv_skey; /* session key */
- uint32_t sv_caps; /* capabilites SMB_CAP_ */
-};
-typedef struct smb_sopt smb_sopt_t;
-
-/*
- * State carried in/out of the driver by the IOD thread.
- * Inside the driver, these are members of the "VC" object.
- */
-struct smb_iods {
- int32_t is_tran_fd; /* transport FD */
- uint32_t is_vcflags; /* SMBV_... */
- uint8_t is_hflags; /* SMB header flags */
- uint16_t is_hflags2; /* SMB header flags2 */
- uint16_t is_smbuid; /* SMB header UID */
- uint16_t is_next_mid; /* SMB header MID */
- uint32_t is_txmax; /* max tx/rx packet size */
- uint32_t is_rwmax; /* max read/write data size */
- uint32_t is_rxmax; /* max readx data size */
- uint32_t is_wxmax; /* max writex data size */
- uint8_t is_ssn_key[SMBIOC_HASH_SZ]; /* session key */
- /* Signing state */
- uint32_t is_next_seq; /* my next sequence number */
- uint32_t is_u_maclen; /* MAC key length */
- lptr_t is_u_mackey; /* user-space ptr! */
-};
-typedef struct smb_iods smb_iods_t;
-
/*
* This is the operational state information passed
* in and out of the driver for SMBIOC_SSN_WORK
*/
struct smbioc_ssn_work {
- smb_iods_t wk_iods;
- smb_sopt_t wk_sopt;
- int wk_out_state;
+ uint32_t wk_out_state; /* out-only */
+ uint32_t wk_u_ssnkey_len; /* ssn key length */
+ lptr_t wk_u_ssnkey_buf; /* user-space ptr! */
+ uint32_t wk_u_auth_rlen; /* recv auth tok len */
+ uint32_t wk_u_auth_wlen; /* send auth tok len */
+ lptr_t wk_u_auth_rbuf; /* recv auth tok buf */
+ lptr_t wk_u_auth_wbuf; /* send auth tok buf */
+ uint8_t wk_cl_guid[16]; /* client GUID */
};
typedef struct smbioc_ssn_work smbioc_ssn_work_t;
@@ -288,66 +268,27 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t;
* User-level SMB requests
*/
-/*
- * SMBIOC_REQUEST (simple SMB request)
- */
-typedef struct smbioc_rq {
- uchar_t ioc_cmd;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint32_t ioc_tbufsz; /* transmit */
- uint32_t ioc_rbufsz; /* receive */
- lptr_t _ioc_tbuf;
- lptr_t _ioc_rbuf;
-} smbioc_rq_t;
-#define ioc_tbuf _ioc_tbuf.lp_ptr
-#define ioc_rbuf _ioc_rbuf.lp_ptr
-
-
-#define SMBIOC_T2RQ_MAXSETUP 4
-#define SMBIOC_T2RQ_MAXNAME 128
-
-typedef struct smbioc_t2rq {
- uint16_t ioc_setup[SMBIOC_T2RQ_MAXSETUP];
- int32_t ioc_setupcnt;
- char ioc_name[SMBIOC_T2RQ_MAXNAME];
- ushort_t ioc_tparamcnt;
- ushort_t ioc_tdatacnt;
- ushort_t ioc_rparamcnt;
- ushort_t ioc_rdatacnt;
- uint8_t ioc__pad1;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint16_t ioc_rpflags2;
- uint16_t ioc__pad2;
- lptr_t _ioc_tparam;
- lptr_t _ioc_tdata;
- lptr_t _ioc_rparam;
- lptr_t _ioc_rdata;
-} smbioc_t2rq_t;
-#define ioc_tparam _ioc_tparam.lp_ptr
-#define ioc_tdata _ioc_tdata.lp_ptr
-#define ioc_rparam _ioc_rparam.lp_ptr
-#define ioc_rdata _ioc_rdata.lp_ptr
-
-
-typedef struct smbioc_flags {
- int32_t ioc_level; /* 0 - session, 1 - share */
- int32_t ioc_flags;
- int32_t ioc_mask;
-} smbioc_flags_t;
-
typedef struct smbioc_rw {
- int32_t ioc_fh;
uint32_t ioc_cnt;
+ uint32_t ioc_flags;
lloff_t _ioc_offset;
lptr_t _ioc_base;
} smbioc_rw_t;
#define ioc_offset _ioc_offset._f
#define ioc_base _ioc_base.lp_ptr
+/* Transact on named pipe (send/recv) */
+typedef struct smbioc_xnp {
+ uint32_t ioc_tdlen; /* transmit len */
+ uint32_t ioc_rdlen; /* recv maxlen */
+ uint32_t ioc_more; /* more data to read */
+ uint32_t ioc_pad1;
+ lptr_t _ioc_tdata;
+ lptr_t _ioc_rdata;
+} smbioc_xnp_t;
+#define ioc_tdata _ioc_tdata.lp_ptr
+#define ioc_rdata _ioc_rdata.lp_ptr
+
typedef struct smbioc_ntcreate {
uint32_t ioc_req_acc;
uint32_t ioc_efattr;
@@ -383,18 +324,16 @@ typedef struct smbioc_pk {
* Keep GETVERS first and use it to verify
* driver compatibility with the library.
*/
-#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
+#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
typedef enum nsmb_ioc {
SMBIOC_GETVERS = SMBIOC_BASE, /* keep first */
- SMBIOC_FLAGS2, /* get hflags2 */
+ SMBIOC_FLAGS2, /* obsolete */
SMBIOC_GETSSNKEY, /* get SMB session key */
SMBIOC_DUP_DEV, /* duplicate dev handle */
- SMBIOC_REQUEST, /* simple request */
- SMBIOC_T2RQ, /* trans2 request */
-
SMBIOC_READ, /* read (pipe) */
SMBIOC_WRITE, /* write (pipe) */
+ SMBIOC_XACTNP, /* "transact" (pipe) */
SMBIOC_NTCREATE, /* open or create */
SMBIOC_PRINTJOB, /* open print job */
SMBIOC_CLOSEFH, /* from ntcreate or printjob */
@@ -409,9 +348,12 @@ typedef enum nsmb_ioc {
SMBIOC_TREE_KILL,
SMBIOC_TREE_RELE,
+ SMBIOC_IOD_CONNECT, /* Setup connection */
+ SMBIOC_IOD_NEGOTIATE, /* SMB/SMB2 negotiate */
+ SMBIOC_IOD_SSNSETUP, /* SMB/SMB2 session setup */
SMBIOC_IOD_WORK, /* work on session requests */
SMBIOC_IOD_IDLE, /* wait for requests on this session */
- SMBIOC_IOD_RCFAIL, /* notify that reconnect failed */
+ SMBIOC_IOD_RCFAIL, /* tell driver reconnect failed */
/* Password Keychain (PK) support. */
SMBIOC_PK_ADD, /* Add/Modify a password entry */
diff --git a/usr/src/uts/common/smb/Makefile b/usr/src/uts/common/smb/Makefile
index 74ac618565..afa0837b2b 100644
--- a/usr/src/uts/common/smb/Makefile
+++ b/usr/src/uts/common/smb/Makefile
@@ -21,7 +21,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
include ../../../Makefile.master
@@ -29,8 +29,10 @@ include ../../../Makefile.master
HDRS= \
doserror.h \
lmerr.h \
+ ntaccess.h \
nterror.h \
ntstatus.h \
+ winioctl.h \
wintypes.h
diff --git a/usr/src/uts/common/smbsrv/ntaccess.h b/usr/src/uts/common/smb/ntaccess.h
index 114150baa9..77d48b48ad 100644
--- a/usr/src/uts/common/smbsrv/ntaccess.h
+++ b/usr/src/uts/common/smb/ntaccess.h
@@ -21,13 +21,13 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_NTACCESS_H
#define _SMBSRV_NTACCESS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This file defines the NT compatible access control masks and values.
* An access mask as a 32-bit value arranged as shown below.
diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smb/winioctl.h
index bbde2e4a6f..a18d7853ce 100644
--- a/usr/src/uts/common/smbsrv/winioctl.h
+++ b/usr/src/uts/common/smb/winioctl.h
@@ -22,10 +22,10 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
-#ifndef _SMBSRV_WINIOCTL_H
-#define _SMBSRV_WINIOCTL_H
+#ifndef _SMB_WINIOCTL_H
+#define _SMB_WINIOCTL_H
/*
* Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++
@@ -544,4 +544,4 @@ extern "C" {
}
#endif
-#endif /* _SMBSRV_WINIOCTL_H */
+#endif /* _SMB_WINIOCTL_H */
diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile
index 4664c09cfb..a80be7497f 100644
--- a/usr/src/uts/common/smbsrv/Makefile
+++ b/usr/src/uts/common/smbsrv/Makefile
@@ -20,7 +20,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
include ../../../Makefile.master
@@ -36,7 +36,6 @@ HDRS= alloc.h \
netbios.h \
netrauth.h \
nmpipes.h \
- ntaccess.h \
ntifs.h \
ntlocale.h \
smb_sid.h \
@@ -61,7 +60,6 @@ HDRS= alloc.h \
smb2_kproto.h \
string.h \
svrapi.h \
- winioctl.h \
winsvc.h
NDLHDRS= dssetup.ndl \
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
index a4986bea78..65e2708569 100644
--- a/usr/src/uts/common/smbsrv/smb.h
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_SMB_H
@@ -39,7 +39,7 @@
#include <smb/nterror.h>
#include <smb/lmerr.h>
#include <smb/doserror.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
/*
* Macintosh Extensions for CIFS
diff --git a/usr/src/uts/common/sys/conf.h b/usr/src/uts/common/sys/conf.h
index 4bf3d5c7e3..148104f83a 100644
--- a/usr/src/uts/common/sys/conf.h
+++ b/usr/src/uts/common/sys/conf.h
@@ -41,11 +41,11 @@
extern "C" {
#endif
-#define FMNAMESZ 8 /* used by struct fmodsw */
+#define FMNAMESZ 8 /* used by struct fmodsw */
#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* XXX Given that drivers need to include this file,
@@ -53,10 +53,14 @@ extern "C" {
* it legitimizes (aka provides prototypes for)
* all sorts of functions that aren't in the DKI/SunDDI
*/
+#include <sys/types.h>
#include <sys/systm.h>
+
+#endif /* _KERNEL || _FAKE_KERNEL */
+#ifdef _KERNEL
+
#include <sys/devops.h>
#include <sys/model.h>
-#include <sys/types.h>
#include <sys/buf.h>
#include <sys/cred.h>
#include <sys/uio.h>
diff --git a/usr/src/uts/common/sys/debug.h b/usr/src/uts/common/sys/debug.h
index e4a959205a..9c91905af2 100644
--- a/usr/src/uts/common/sys/debug.h
+++ b/usr/src/uts/common/sys/debug.h
@@ -138,12 +138,12 @@ _NOTE(CONSTCOND) } while (0)
#define __CTASSERT(x, y) \
typedef char __compile_time_assertion__ ## y [(x) ? 1 : -1] __unused
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern void abort_sequence_enter(char *);
extern void debug_enter(char *);
-#endif /* _KERNEL */
+#endif /* _KERNEL || _FAKE_KERNEL */
#if defined(DEBUG) && !defined(__sun)
/* CSTYLED */
diff --git a/usr/src/uts/common/sys/dirent.h b/usr/src/uts/common/sys/dirent.h
index 114fcf6e30..c079fb983a 100644
--- a/usr/src/uts/common/sys/dirent.h
+++ b/usr/src/uts/common/sys/dirent.h
@@ -76,7 +76,7 @@ typedef struct dirent64 {
#endif /* _LARGEFILE64_SOURCE */
#if !defined(__XOPEN_OR_POSIX) || defined(__EXTENSIONS__)
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#define DIRENT64_RECLEN(namelen) \
((offsetof(dirent64_t, d_name[0]) + 1 + (namelen) + 7) & ~ 7)
#define DIRENT64_NAMELEN(reclen) \
diff --git a/usr/src/uts/common/sys/dnlc.h b/usr/src/uts/common/sys/dnlc.h
index bf947659d0..4a5c20d6d0 100644
--- a/usr/src/uts/common/sys/dnlc.h
+++ b/usr/src/uts/common/sys/dnlc.h
@@ -76,7 +76,7 @@ extern "C" {
* storing full names, then we are ok. The space savings are worth it.
*/
typedef struct ncache {
- struct ncache *hash_next; /* hash chain, MUST BE FIRST */
+ struct ncache *hash_next; /* hash chain, MUST BE FIRST */
struct ncache *hash_prev;
struct vnode *vp; /* vnode the name refers to */
struct vnode *dp; /* vnode of parent of name */
@@ -169,7 +169,7 @@ struct nc_stats {
(namlen) = Xcp - (name); \
}
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/vfs.h>
#include <sys/vnode.h>
@@ -205,7 +205,7 @@ void dnlc_reduce_cache(void *);
*/
typedef struct dcfree {
uint64_t df_handle; /* fs supplied handle */
- struct dcfree *df_next; /* link to next free entry in bucket */
+ struct dcfree *df_next; /* link to next free entry in bucket */
uint_t df_len; /* length of free entry */
} dcfree_t;
diff --git a/usr/src/uts/common/sys/file.h b/usr/src/uts/common/sys/file.h
index eb1328f38d..b0914cfb45 100644
--- a/usr/src/uts/common/sys/file.h
+++ b/usr/src/uts/common/sys/file.h
@@ -119,7 +119,7 @@ typedef struct fpollinfo {
#define FCLOEXEC 0x800000 /* O_CLOEXEC = 0x800000 */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Fake flags for driver ioctl calls to inform them of the originating
@@ -183,7 +183,7 @@ typedef struct fpollinfo {
extern int flock(int, int);
#endif
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Routines dealing with user per-open file flags and
@@ -192,15 +192,16 @@ extern int flock(int, int);
struct proc; /* forward reference for function prototype */
struct vnodeops;
struct vattr;
+struct uf_info;
extern file_t *getf(int);
extern file_t *getf_gen(int, uf_entry_gen_t *);
extern void releasef(int);
-extern void areleasef(int, uf_info_t *);
+extern void areleasef(int, struct uf_info *);
#ifndef _BOOT
-extern void closeall(uf_info_t *);
+extern void closeall(struct uf_info *);
#endif
-extern void flist_fork(uf_info_t *, uf_info_t *);
+extern void flist_fork(struct uf_info *, struct uf_info *);
extern int closef(file_t *);
extern int closeandsetf(int, file_t *);
extern int ufalloc_file(int, file_t *);
@@ -217,8 +218,8 @@ extern void f_setfd(int, char);
extern int f_getfl(int, int *);
extern int f_badfd(int, int *, int);
extern int fassign(struct vnode **, int, int *);
-extern void fcnt_add(uf_info_t *, int);
-extern void close_exec(uf_info_t *);
+extern void fcnt_add(struct uf_info *, int);
+extern void close_exec(struct uf_info *);
extern void clear_stale_fd(void);
extern void clear_active_fd(int);
extern void set_active_fd(int);
diff --git a/usr/src/uts/common/sys/model.h b/usr/src/uts/common/sys/model.h
index fab96bbe00..0569c086f5 100644
--- a/usr/src/uts/common/sys/model.h
+++ b/usr/src/uts/common/sys/model.h
@@ -37,7 +37,7 @@ extern "C" {
#include <sys/isa_defs.h>
-#if defined(_KERNEL) || defined(_KMEMUSER)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
/*
* These bits are used in various places to specify the data model
diff --git a/usr/src/uts/common/sys/modhash.h b/usr/src/uts/common/sys/modhash.h
index 68d1c4dedd..7f7103ecb9 100644
--- a/usr/src/uts/common/sys/modhash.h
+++ b/usr/src/uts/common/sys/modhash.h
@@ -34,7 +34,7 @@
extern "C" {
#endif
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/types.h>
diff --git a/usr/src/uts/common/sys/poll.h b/usr/src/uts/common/sys/poll.h
index 4434a8551a..558edbfba9 100644
--- a/usr/src/uts/common/sys/poll.h
+++ b/usr/src/uts/common/sys/poll.h
@@ -96,7 +96,7 @@ typedef unsigned long nfds_t;
#endif /* _KERNEL */
-#if defined(_KERNEL) || defined(_KMEMUSER)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
#include <sys/thread.h>
diff --git a/usr/src/uts/common/sys/share.h b/usr/src/uts/common/sys/share.h
index 4de5f5ce65..1a8aead065 100644
--- a/usr/src/uts/common/sys/share.h
+++ b/usr/src/uts/common/sys/share.h
@@ -63,7 +63,7 @@ struct shrlocklist {
struct shrlocklist *next;
};
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
struct flock64;
extern int add_share(struct vnode *, struct shrlock *);
diff --git a/usr/src/uts/common/sys/signal.h b/usr/src/uts/common/sys/signal.h
index 1818665b45..b12dff6034 100644
--- a/usr/src/uts/common/sys/signal.h
+++ b/usr/src/uts/common/sys/signal.h
@@ -246,7 +246,7 @@ struct sigstack {
#include <sys/ucontext.h>
#endif /* defined(_XPG4_2) */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/t_lock.h>
extern const k_sigset_t nullsmask; /* a null signal mask */
diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h
index efcd2a9194..7488d3dee8 100644
--- a/usr/src/uts/common/sys/stream.h
+++ b/usr/src/uts/common/sys/stream.h
@@ -36,7 +36,7 @@
* For source compatibility
*/
#include <sys/isa_defs.h>
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/kmem.h>
#include <sys/uio.h>
#endif
@@ -641,7 +641,7 @@ struct stroptions {
#define SO_MAXBLK 0x100000 /* set maximum message block size */
#define SO_TAIL 0x200000 /* set the extra allocated space */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Structure for rw (read/write) procedure calls. A pointer
* to a struiod_t is passed as a parameter to the rwnext() call.
@@ -766,7 +766,7 @@ typedef struct cmdblk {
*/
#define bpsize(bp) ((unsigned int)(bp->b_datap->db_lim - bp->b_datap->db_base))
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* For two-byte M_ERROR messages: indication that a side does not have an error
diff --git a/usr/src/uts/common/sys/strsubr.h b/usr/src/uts/common/sys/strsubr.h
index 0f29dd3675..f3bc1ed407 100644
--- a/usr/src/uts/common/sys/strsubr.h
+++ b/usr/src/uts/common/sys/strsubr.h
@@ -40,6 +40,7 @@
*/
#include <sys/stream.h>
#include <sys/stropts.h>
+#include <sys/vnode.h>
#include <sys/kstat.h>
#include <sys/uio.h>
#include <sys/proc.h>
@@ -115,7 +116,7 @@ extern "C" {
/*
* Function types for the parameterized stream head.
* The msgfunc_t takes the parameters:
- * msgfunc(vnode_t *vp, mblk_t *mp, strwakeup_t *wakeups,
+ * msgfunc(vnode_t *vp, mblk_t *mp, strwakeup_t *wakeups,
* strsigset_t *firstmsgsigs, strsigset_t *allmsgsigs,
* strpollset_t *pollwakeups);
* It returns an optional message to be processed by the stream head.
@@ -130,7 +131,7 @@ typedef short strpollset_t;
typedef uintptr_t callbparams_id_t;
typedef mblk_t *(*msgfunc_t)(vnode_t *, mblk_t *, strwakeup_t *,
strsigset_t *, strsigset_t *, strpollset_t *);
-typedef int (*errfunc_t)(vnode_t *, int, int *);
+typedef int (*errfunc_t)(vnode_t *, int, int *);
/*
* Per stream sd_lock in putnext may be replaced by per cpu stream_putlocks
@@ -276,7 +277,7 @@ typedef struct stdata {
/* 0x00020000 unused */
/* 0x00040000 unused */
#define STRTOSTOP 0x00080000 /* block background writes */
-#define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */
+#define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */
/* 0x00200000 unused */
#define STRMOUNT 0x00400000 /* stream is mounted */
#define STRNOTATMARK 0x00800000 /* Not at mark (when empty read q) */
@@ -410,7 +411,7 @@ typedef struct stdata {
*
* The new way is:
*
- * mutex_enter(SQLOCK(sq));
+ * mutex_enter(SQLOCK(sq));
* count = sq->sq_count;
* SQ_PUTLOCKS_ENTER(sq);
* SUM_SQ_PUTCOUNTS(sq, count);
@@ -459,8 +460,8 @@ struct syncq {
*/
uint16_t sq_type; /* type (concurrency) of syncq */
uint16_t sq_rmqcount; /* # threads inside removeq() */
- kcondvar_t sq_wait; /* block on this sync queue */
- kcondvar_t sq_exitwait; /* waiting for thread to leave the */
+ kcondvar_t sq_wait; /* block on this sync queue */
+ kcondvar_t sq_exitwait; /* waiting for thread to leave the */
/* inner perimeter */
/*
* Handling synchronous callbacks such as qtimeout and qbufcall
@@ -1024,7 +1025,7 @@ typedef struct str_stack str_stack_t;
/*
* Copy modes for tty and I_STR ioctls
*/
-#define U_TO_K 01 /* User to Kernel */
+#define U_TO_K 01 /* User to Kernel */
#define K_TO_K 02 /* Kernel to Kernel */
/*
@@ -1077,7 +1078,7 @@ typedef struct str_stack str_stack_t;
#define STRUNLOCKMATES(X) mutex_exit(&((X)->sd_lock)); \
mutex_exit(&(((X)->sd_mate)->sd_lock))
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern void strinit(void);
extern int strdoioctl(struct stdata *, struct strioctl *, int, int,
diff --git a/usr/src/uts/common/sys/t_kuser.h b/usr/src/uts/common/sys/t_kuser.h
index 7aac9d94d2..b3c4da657c 100644
--- a/usr/src/uts/common/sys/t_kuser.h
+++ b/usr/src/uts/common/sys/t_kuser.h
@@ -98,6 +98,7 @@ extern int t_kconnect(TIUSER *, struct t_call *, struct t_call *);
extern int t_kfree(TIUSER *, char *, int);
extern int t_kgetstate(TIUSER *, int *);
extern int t_kopen(struct file *, dev_t, int, TIUSER **, struct cred *);
+extern int t_koptmgmt(TIUSER *, struct t_optmgmt *, struct t_optmgmt *);
extern int t_krcvudata(TIUSER *, struct t_kunitdata *, int *, int *);
extern int t_ksndudata(TIUSER *, struct t_kunitdata *, frtn_t *);
extern int t_kspoll(TIUSER *, int, int, int *);
diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref
index 9d670f24c3..7476bc696d 100644
--- a/usr/src/uts/intel/nsmb/ioc_check.ref
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref
@@ -3,10 +3,12 @@
#define ID_DOMAIN_INCR 0x1
#define ID_USER 0x120
#define ID_USER_INCR 0x1
-#define SSN_VOPT 0x0
-#define SSN_OWNER 0x4
-#define SSN_ID 0x8
-#define SSN_SRVNAME 0x228
+#define SSN_OWNER 0x0
+#define SSN_VOPT 0x4
+#define SSN_MINVER 0x8
+#define SSN_MAXVER 0xa
+#define SSN_ID 0xc
+#define SSN_SRVNAME 0x22c
#define SSN_SRVNAME_INCR 0x1
#define SH_USE 0x0
#define SH_TYPE 0x4
@@ -17,70 +19,27 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#define WK_CL_GUID 0x28
+#define WK_CL_GUID_INCR 0x1
#define SIZEOF_SMBIOC_RW 0x18
-#define IOC_FH 0x0
-#define IOC_CNT 0x4
+#define IOC_CNT 0x0
+#define IOC_FLAGS 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_TDLEN 0x0
+#define IOC_RDLEN 0x4
+#define IOC_MORE 0x8
+#define IOC_PAD1 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_NTCREATE 0x114
#define IOC_REQ_ACC 0x0
#define IOC_EFATTR 0x4
diff --git a/usr/src/uts/intel/pcbe/core_pcbe.c b/usr/src/uts/intel/pcbe/core_pcbe.c
index 7424e2526b..ad92c2f62f 100644
--- a/usr/src/uts/intel/pcbe/core_pcbe.c
+++ b/usr/src/uts/intel/pcbe/core_pcbe.c
@@ -994,7 +994,8 @@ core_pcbe_event_coverage(char *event)
} else {
if (find_generic_events(event, cmn_generic_events) != NULL) {
bitmap |= BITMASK_XBITS(num_gpc);
- } if (find_generic_events(event, generic_events_pic0) != NULL) {
+ } else if (find_generic_events(event,
+ generic_events_pic0) != NULL) {
bitmap |= 1ULL;
} else if (find_gpcevent_core_uarch(event,
cmn_gpc_events_core_uarch) != NULL) {
diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref
index 9d670f24c3..7476bc696d 100644
--- a/usr/src/uts/sparc/nsmb/ioc_check.ref
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref
@@ -3,10 +3,12 @@
#define ID_DOMAIN_INCR 0x1
#define ID_USER 0x120
#define ID_USER_INCR 0x1
-#define SSN_VOPT 0x0
-#define SSN_OWNER 0x4
-#define SSN_ID 0x8
-#define SSN_SRVNAME 0x228
+#define SSN_OWNER 0x0
+#define SSN_VOPT 0x4
+#define SSN_MINVER 0x8
+#define SSN_MAXVER 0xa
+#define SSN_ID 0xc
+#define SSN_SRVNAME 0x22c
#define SSN_SRVNAME_INCR 0x1
#define SH_USE 0x0
#define SH_TYPE 0x4
@@ -17,70 +19,27 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#define WK_CL_GUID 0x28
+#define WK_CL_GUID_INCR 0x1
#define SIZEOF_SMBIOC_RW 0x18
-#define IOC_FH 0x0
-#define IOC_CNT 0x4
+#define IOC_CNT 0x0
+#define IOC_FLAGS 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_TDLEN 0x0
+#define IOC_RDLEN 0x4
+#define IOC_MORE 0x8
+#define IOC_PAD1 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_NTCREATE 0x114
#define IOC_REQ_ACC 0x0
#define IOC_EFATTR 0x4